Try to use broadcast for su logging and notify
In commit 8d4c407, native Magisk always launches an activity for communicating with Magisk Manager. While this works extremely well, since it also workaround stupid OEMs that blocks broadcasts, it has a problem: launching an activity will claim the focus of the device, which could be super annoying in some circumstances. This commit adds a new feature to run a broadcast test on boot complete. If Magisk Manager successfully receives the broadcast, it will toggle a setting in magiskd so all future su loggings and notifies will always use broadcasts instead of launching activities. Fix #1412
This commit is contained in:
parent
89275270f3
commit
80cd85b061
@ -1,84 +0,0 @@
|
||||
package com.topjohnwu.magisk.model.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.topjohnwu.magisk.App;
|
||||
import com.topjohnwu.magisk.ClassMap;
|
||||
import com.topjohnwu.magisk.Config;
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity;
|
||||
import com.topjohnwu.magisk.utils.DownloadApp;
|
||||
import com.topjohnwu.magisk.utils.SuLogger;
|
||||
import com.topjohnwu.magisk.view.Notifications;
|
||||
import com.topjohnwu.magisk.view.Shortcuts;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
public class GeneralReceiver extends BroadcastReceiver {
|
||||
|
||||
private String getPkg(Intent i) {
|
||||
return i.getData() == null ? "" : i.getData().getEncodedSchemeSpecificPart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
App app = App.self;
|
||||
if (intent == null)
|
||||
return;
|
||||
String action = intent.getAction();
|
||||
if (action == null)
|
||||
return;
|
||||
switch (action) {
|
||||
case Intent.ACTION_REBOOT:
|
||||
case Intent.ACTION_BOOT_COMPLETED:
|
||||
action = intent.getStringExtra("action");
|
||||
if (action == null) {
|
||||
// Actual boot completed event
|
||||
Shell.su("mm_patch_dtbo").submit(result -> {
|
||||
if (result.isSuccess())
|
||||
Notifications.dtboPatched();
|
||||
});
|
||||
break;
|
||||
}
|
||||
switch (action) {
|
||||
case SuRequestActivity.REQUEST:
|
||||
Intent i = new Intent(app, ClassMap.get(SuRequestActivity.class))
|
||||
.setAction(action)
|
||||
.putExtra("socket", intent.getStringExtra("socket"))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
|
||||
app.startActivity(i);
|
||||
break;
|
||||
case SuRequestActivity.LOG:
|
||||
SuLogger.handleLogs(intent);
|
||||
break;
|
||||
case SuRequestActivity.NOTIFY:
|
||||
SuLogger.handleNotify(intent);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Intent.ACTION_PACKAGE_REPLACED:
|
||||
// This will only work pre-O
|
||||
if (Config.get(Config.Key.SU_REAUTH)) {
|
||||
app.getDB().deletePolicy(getPkg(intent));
|
||||
}
|
||||
break;
|
||||
case Intent.ACTION_PACKAGE_FULLY_REMOVED:
|
||||
String pkg = getPkg(intent);
|
||||
app.getDB().deletePolicy(pkg);
|
||||
Shell.su("magiskhide --rm " + pkg).submit();
|
||||
break;
|
||||
case Intent.ACTION_LOCALE_CHANGED:
|
||||
Shortcuts.setup(context);
|
||||
break;
|
||||
case Const.Key.BROADCAST_MANAGER_UPDATE:
|
||||
Config.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK);
|
||||
DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME));
|
||||
break;
|
||||
case Const.Key.BROADCAST_REBOOT:
|
||||
Shell.su("/system/bin/reboot").submit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.topjohnwu.magisk.model.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.topjohnwu.magisk.ClassMap
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.data.database.MagiskDB
|
||||
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
|
||||
import com.topjohnwu.magisk.utils.DownloadApp
|
||||
import com.topjohnwu.magisk.utils.RootUtils
|
||||
import com.topjohnwu.magisk.utils.SuLogger
|
||||
import com.topjohnwu.magisk.utils.get
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
open class GeneralReceiver : BroadcastReceiver() {
|
||||
|
||||
companion object {
|
||||
const val REQUEST = "request"
|
||||
const val LOG = "log"
|
||||
const val NOTIFY = "notify"
|
||||
const val TEST = "test"
|
||||
}
|
||||
|
||||
private fun getPkg(intent: Intent): String {
|
||||
return intent.data?.encodedSchemeSpecificPart ?: ""
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent?) {
|
||||
if (intent == null)
|
||||
return
|
||||
val mDB: MagiskDB = get()
|
||||
var action: String? = intent.action ?: return
|
||||
when (action) {
|
||||
Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> {
|
||||
action = intent.getStringExtra("action")
|
||||
if (action == null) {
|
||||
// Actual boot completed event
|
||||
Shell.su("mm_patch_dtbo").submit { result ->
|
||||
if (result.isSuccess)
|
||||
Notifications.dtboPatched()
|
||||
}
|
||||
return
|
||||
}
|
||||
when (action) {
|
||||
REQUEST -> {
|
||||
val i = Intent(context, ClassMap.get<Any>(SuRequestActivity::class.java))
|
||||
.setAction(action)
|
||||
.putExtra("socket", intent.getStringExtra("socket"))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
|
||||
context.startActivity(i)
|
||||
}
|
||||
LOG -> SuLogger.handleLogs(intent)
|
||||
NOTIFY -> SuLogger.handleNotify(intent)
|
||||
TEST -> Shell.su("magisk --use-broadcast").submit()
|
||||
}
|
||||
}
|
||||
Intent.ACTION_PACKAGE_REPLACED ->
|
||||
// This will only work pre-O
|
||||
if (Config.get<Boolean>(Config.Key.SU_REAUTH)!!) {
|
||||
mDB.deletePolicy(getPkg(intent))
|
||||
}
|
||||
Intent.ACTION_PACKAGE_FULLY_REMOVED -> {
|
||||
val pkg = getPkg(intent)
|
||||
mDB.deletePolicy(pkg)
|
||||
Shell.su("magiskhide --rm $pkg").submit()
|
||||
}
|
||||
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context)
|
||||
Const.Key.BROADCAST_MANAGER_UPDATE -> {
|
||||
Config.managerLink = intent.getStringExtra(Const.Key.INTENT_SET_LINK)
|
||||
DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME))
|
||||
}
|
||||
Const.Key.BROADCAST_REBOOT -> RootUtils.reboot()
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
|
||||
import com.topjohnwu.magisk.model.entity.Policy
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||
import com.topjohnwu.magisk.ui.base.MagiskActivity
|
||||
import com.topjohnwu.magisk.utils.SuLogger
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
@ -31,15 +32,15 @@ open class SuRequestActivity : MagiskActivity<SuRequestViewModel, ActivityReques
|
||||
val intent = intent
|
||||
val action = intent.action
|
||||
|
||||
if (TextUtils.equals(action, REQUEST)) {
|
||||
if (TextUtils.equals(action, GeneralReceiver.REQUEST)) {
|
||||
if (!viewModel.handleRequest(intent) {})
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
if (TextUtils.equals(action, LOG))
|
||||
if (TextUtils.equals(action, GeneralReceiver.LOG))
|
||||
SuLogger.handleLogs(intent)
|
||||
else if (TextUtils.equals(action, NOTIFY))
|
||||
else if (TextUtils.equals(action, GeneralReceiver.NOTIFY))
|
||||
SuLogger.handleNotify(intent)
|
||||
|
||||
finish()
|
||||
@ -58,10 +59,4 @@ open class SuRequestActivity : MagiskActivity<SuRequestViewModel, ActivityReques
|
||||
else
|
||||
ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REQUEST = "request"
|
||||
const val LOG = "log"
|
||||
const val NOTIFY = "notify"
|
||||
}
|
||||
}
|
||||
|
@ -732,4 +732,7 @@ void boot_complete(int client) {
|
||||
install_apk("/data/magisk.apk");
|
||||
}
|
||||
}
|
||||
|
||||
// Test whether broadcast can be used or not
|
||||
broadcast_test();
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ static void *request_handler(void *args) {
|
||||
case LATE_START:
|
||||
case BOOT_COMPLETE:
|
||||
case SQLITE_CMD:
|
||||
case BROADCAST_ACK:
|
||||
if (credential.uid != 0) {
|
||||
write_int(client, ROOT_REQUIRED);
|
||||
close(client);
|
||||
@ -90,6 +91,10 @@ static void *request_handler(void *args) {
|
||||
case SQLITE_CMD:
|
||||
exec_sql(client);
|
||||
break;
|
||||
case BROADCAST_ACK:
|
||||
LOGD("* Use broadcasts for su logging and notify\n");
|
||||
CONNECT_BROADCAST = true;
|
||||
close(client);
|
||||
default:
|
||||
close(client);
|
||||
break;
|
||||
|
@ -233,7 +233,7 @@ int get_db_strings(db_strings &str, int key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_uid_policy(int uid, su_access &su) {
|
||||
int get_uid_policy(su_access &su, int uid) {
|
||||
char query[256], *err;
|
||||
sprintf(query, "SELECT policy, logging, notification FROM policies "
|
||||
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <db.h>
|
||||
#include <flags.h>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
[[noreturn]] static void usage() {
|
||||
fprintf(stderr,
|
||||
FULL_VER(Magisk) " multi-call binary\n"
|
||||
@ -33,6 +35,7 @@
|
||||
" --clone-attr SRC DEST clone permission, owner, and selinux context\n"
|
||||
" --clone SRC DEST clone SRC to DEST\n"
|
||||
" --sqlite SQL exec SQL to Magisk database\n"
|
||||
" --use-broadcast use broadcast for su logging and notify\n"
|
||||
"\n"
|
||||
"Supported init triggers:\n"
|
||||
" post-fs-data, service, boot-complete\n"
|
||||
@ -48,66 +51,70 @@
|
||||
int magisk_main(int argc, char *argv[]) {
|
||||
if (argc < 2)
|
||||
usage();
|
||||
if (strcmp(argv[1], "-c") == 0) {
|
||||
if (argv[1] == "-c"sv) {
|
||||
printf(MAGISK_VERSION ":MAGISK (" str(MAGISK_VER_CODE) ")\n");
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "-v") == 0) {
|
||||
} else if (argv[1] == "-v"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION);
|
||||
char *v = read_string(fd);
|
||||
printf("%s\n", v);
|
||||
free(v);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "-V") == 0) {
|
||||
} else if (argv[1] == "-V"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, CHECK_VERSION_CODE);
|
||||
printf("%d\n", read_int(fd));
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--list") == 0) {
|
||||
} else if (argv[1] == "--list"sv) {
|
||||
for (int i = 0; applet_names[i]; ++i)
|
||||
printf("%s\n", applet_names[i]);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--unlock-blocks") == 0) {
|
||||
} else if (argv[1] == "--unlock-blocks"sv) {
|
||||
unlock_blocks();
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--restorecon") == 0) {
|
||||
} else if (argv[1] == "--restorecon"sv) {
|
||||
restore_rootcon();
|
||||
restorecon();
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--clone-attr") == 0) {
|
||||
} else if (argv[1] == "--clone-attr"sv) {
|
||||
if (argc < 4) usage();
|
||||
clone_attr(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--clone") == 0) {
|
||||
} else if (argv[1] == "--clone"sv) {
|
||||
if (argc < 4) usage();
|
||||
cp_afc(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--daemon") == 0) {
|
||||
} else if (argv[1] == "--daemon"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, DO_NOTHING);
|
||||
return 0;
|
||||
} else if (strcmp(argv[1], "--post-fs-data") == 0) {
|
||||
} else if (argv[1] == "--post-fs-data"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, POST_FS_DATA);
|
||||
return read_int(fd);
|
||||
} else if (strcmp(argv[1], "--service") == 0) {
|
||||
} else if (argv[1] == "--service"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, LATE_START);
|
||||
return read_int(fd);
|
||||
} else if (strcmp(argv[1], "--boot-complete") == 0) {
|
||||
} else if (argv[1] == "--boot-complete"sv) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, BOOT_COMPLETE);
|
||||
return read_int(fd);
|
||||
} else if (strcmp(argv[1], "--sqlite") == 0) {
|
||||
} else if (argv[1] == "--sqlite"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, SQLITE_CMD);
|
||||
write_string(fd, argv[2]);
|
||||
send_fd(fd, STDOUT_FILENO);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--use-broadcast"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, BROADCAST_ACK);
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
/* Entry point for testing stuffs */
|
||||
else if (strcmp(argv[1], "--test") == 0) {
|
||||
else if (argv[1] == "--test"sv) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -17,7 +17,7 @@ enum {
|
||||
BOOT_COMPLETE,
|
||||
MAGISKHIDE,
|
||||
SQLITE_CMD,
|
||||
ZYGOTE_NOTIFY,
|
||||
BROADCAST_ACK,
|
||||
};
|
||||
|
||||
// Return codes for daemon
|
||||
@ -82,6 +82,8 @@ void magiskhide_handler(int client);
|
||||
*************/
|
||||
|
||||
void su_daemon_handler(int client, struct ucred *credential);
|
||||
void broadcast_test();
|
||||
|
||||
extern int SDK_INT;
|
||||
extern bool RECOVERY_MODE;
|
||||
extern bool CONNECT_BROADCAST;
|
||||
|
@ -154,7 +154,7 @@ typedef std::function<bool(db_row&)> db_row_cb;
|
||||
|
||||
int get_db_settings(db_settings &cfg, int key = -1);
|
||||
int get_db_strings(db_strings &str, int key = -1);
|
||||
int get_uid_policy(int uid, su_access &su);
|
||||
int get_uid_policy(su_access &su, int uid);
|
||||
int validate_manager(std::string &alt_pkg, int userid, struct stat *st);
|
||||
void exec_sql(int client);
|
||||
char *db_exec(const char *sql);
|
||||
|
@ -11,12 +11,21 @@
|
||||
|
||||
#include "su.h"
|
||||
|
||||
bool CONNECT_BROADCAST;
|
||||
|
||||
#define START_ACTIVITY \
|
||||
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
|
||||
"start", "-n", nullptr, "--user", nullptr, "-f", "0x18000020", "-a"
|
||||
|
||||
// 0x18000020 = FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_INCLUDE_STOPPED_PACKAGES
|
||||
|
||||
#define START_BROADCAST \
|
||||
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
|
||||
"broadcast", "-n", nullptr, "--user", nullptr, "-f", "0x00000020", \
|
||||
"-a", "android.intent.action.REBOOT", "--es", "action"
|
||||
|
||||
// 0x00000020 = FLAG_INCLUDE_STOPPED_PACKAGES
|
||||
|
||||
static inline const char *get_command(const su_request *to) {
|
||||
if (to->command[0])
|
||||
return to->command;
|
||||
@ -39,9 +48,9 @@ static inline void get_uid(char *uid, su_info *info) {
|
||||
: info->uid);
|
||||
}
|
||||
|
||||
static void silent_run(const char **args, su_info *info) {
|
||||
static void exec_am_cmd(const char **args, su_info *info) {
|
||||
char component[128];
|
||||
sprintf(component, "%s/a.m", info->str[SU_MANAGER].data());
|
||||
sprintf(component, "%s/%s", info->str[SU_MANAGER].data(), args[3][0] == 'b' ? "a.h" : "a.m");
|
||||
char user[8];
|
||||
get_user(user, info);
|
||||
|
||||
@ -62,6 +71,16 @@ static void silent_run(const char **args, su_info *info) {
|
||||
exec_command(exec);
|
||||
}
|
||||
|
||||
#define LOG_BODY \
|
||||
"log", \
|
||||
"--ei", "from.uid", fromUid, \
|
||||
"--ei", "to.uid", toUid, \
|
||||
"--ei", "pid", pid, \
|
||||
"--ei", "policy", policy, \
|
||||
"--es", "command", get_command(&ctx->req), \
|
||||
"--ez", "notify", ctx->info->access.notify ? "true" : "false", \
|
||||
nullptr
|
||||
|
||||
void app_log(su_context *ctx) {
|
||||
char fromUid[8];
|
||||
get_uid(fromUid, ctx->info);
|
||||
@ -75,19 +94,21 @@ void app_log(su_context *ctx) {
|
||||
char policy[2];
|
||||
sprintf(policy, "%d", ctx->info->access.policy);
|
||||
|
||||
const char *cmd[] = {
|
||||
START_ACTIVITY, "log",
|
||||
"--ei", "from.uid", fromUid,
|
||||
"--ei", "to.uid", toUid,
|
||||
"--ei", "pid", pid,
|
||||
"--ei", "policy", policy,
|
||||
"--es", "command", get_command(&ctx->req),
|
||||
"--ez", "notify", ctx->info->access.notify ? "true" : "false",
|
||||
nullptr
|
||||
};
|
||||
silent_run(cmd, ctx->info);
|
||||
if (CONNECT_BROADCAST) {
|
||||
const char *cmd[] = { START_BROADCAST, LOG_BODY };
|
||||
exec_am_cmd(cmd, ctx->info);
|
||||
} else {
|
||||
const char *cmd[] = { START_ACTIVITY, LOG_BODY };
|
||||
exec_am_cmd(cmd, ctx->info);
|
||||
}
|
||||
}
|
||||
|
||||
#define NOTIFY_BODY \
|
||||
"notify", \
|
||||
"--ei", "from.uid", fromUid, \
|
||||
"--ei", "policy", policy, \
|
||||
nullptr
|
||||
|
||||
void app_notify(su_context *ctx) {
|
||||
char fromUid[8];
|
||||
get_uid(fromUid, ctx->info);
|
||||
@ -95,13 +116,14 @@ void app_notify(su_context *ctx) {
|
||||
char policy[2];
|
||||
sprintf(policy, "%d", ctx->info->access.policy);
|
||||
|
||||
const char *cmd[] = {
|
||||
START_ACTIVITY, "notify",
|
||||
"--ei", "from.uid", fromUid,
|
||||
"--ei", "policy", policy,
|
||||
nullptr
|
||||
};
|
||||
silent_run(cmd, ctx->info);
|
||||
if (CONNECT_BROADCAST) {
|
||||
const char *cmd[] = { START_BROADCAST, NOTIFY_BODY };
|
||||
exec_am_cmd(cmd, ctx->info);
|
||||
} else {
|
||||
const char *cmd[] = { START_ACTIVITY, NOTIFY_BODY };
|
||||
exec_am_cmd(cmd, ctx->info);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void app_connect(const char *socket, su_info *info) {
|
||||
@ -110,7 +132,17 @@ void app_connect(const char *socket, su_info *info) {
|
||||
"--es", "socket", socket,
|
||||
nullptr
|
||||
};
|
||||
silent_run(cmd, info);
|
||||
exec_am_cmd(cmd, info);
|
||||
}
|
||||
|
||||
void broadcast_test() {
|
||||
su_info info;
|
||||
get_db_settings(info.cfg);
|
||||
get_db_strings(info.str);
|
||||
validate_manager(info.str[SU_MANAGER], 0, &info.mgr_st);
|
||||
|
||||
const char *cmd[] = { START_BROADCAST, "test", nullptr };
|
||||
exec_am_cmd(cmd, &info);
|
||||
}
|
||||
|
||||
void socket_send_request(int fd, su_info *info) {
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
int ref;
|
||||
time_t timestamp;
|
||||
|
||||
su_info(unsigned uid);
|
||||
su_info(unsigned uid = 0);
|
||||
~su_info();
|
||||
void lock();
|
||||
void unlock();
|
||||
|
@ -83,7 +83,7 @@ static void database_check(su_info *info) {
|
||||
}
|
||||
|
||||
if (uid > 0)
|
||||
get_uid_policy(uid, info->access);
|
||||
get_uid_policy(info->access, uid);
|
||||
|
||||
// We need to check our manager
|
||||
if (info->access.log || info->access.notify)
|
||||
|
Loading…
x
Reference in New Issue
Block a user