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:
topjohnwu
2019-05-13 02:01:10 -07:00
parent 89275270f3
commit 80cd85b061
12 changed files with 173 additions and 133 deletions

View File

@@ -732,4 +732,7 @@ void boot_complete(int client) {
install_apk("/data/magisk.apk");
}
}
// Test whether broadcast can be used or not
broadcast_test();
}

View File

@@ -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;

View File

@@ -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));

View File

@@ -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

View File

@@ -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;

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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)