Androidインストールサービスのインストール済みソースコード分析



Android Installation Services Installd Source Code Analysis



Androidシステムでは、すべてのインストールのPackageManagerServiceがアプリケーションパッケージと情報管理システムをアンインストールしますが、アプリケーションPackageManagerServiceのインストールとアンインストールは行われず、PackageManagerService installdを介してサービスにアクセスし、インストールパッケージとアンインストールを実行します。




PackageManagerServiceは、途中のソケットを介してinstalldサービスプロセスにアクセスします。Androidスタートアップスクリプトinit.rcで、installdサービス構成によってサービスプロセスを開始します。




上記の構成により、initプロセスはサービスプロセスのインストールを開始します。インストールされたソースはフレームワーク/ベース/ cmds / installdにあります


インストールされたサービスプロセス入力機能:



int main(const int argc, const char *argv[]) { char buf[BUFFER_MAX] struct sockaddr addr socklen_t alen int lsocket, s, count // initialize some global variables if (initialize_globals() <0) { ALOGE('Could not initialize globals exiting. ') exit(1) } // Initialize the installation directory if (initialize_directories() < 0) { ALOGE('Could not create directories exiting. ') exit(1) } // Get installd socket handle all socket system to ANDROID_SOCKET_ [name] is key, socket handle is the way value is stored in the environment variable // lsocket = android_get_control_socket(SOCKET_PATH) if (lsocket < 0) { ALOGE('Failed to get socket from environment: %s ', strerror(errno)) exit(1) } // Listen to the socket if (listen(lsocket, 5)) { ALOGE('Listen on socket failed: %s ', strerror(errno)) exit(1) } // modify the properties of the socket fcntl(lsocket, F_SETFD, FD_CLOEXEC) for () { alen = sizeof(addr) // loop waiting for a client request received s = accept(lsocket, &addr, &alen) if (s < 0) { ALOGE('Accept failed: %s ', strerror(errno)) continue } // After receiving the request from the client, the client requests to modify properties socket fcntl(s, F_SETFD, FD_CLOEXEC) ALOGI('new connection ') // loop to read the contents of the client socket until the reading is empty so far // client sends data format: | data length | data content | for () { unsigned short count // read data length, the reading is successful returns 0, otherwise -1 if (readx(s, &count, sizeof(count))) { ALOGE('failed to read size ') break } // If the read was successful, but the read data length exceeds 1024 bytes, the same stops reading if ((count = BUFFER_MAX)) { ALOGE('invalid size %d ', count) break } // read the data content read successfully returns 0, otherwise -1 if (readx(s, buf, count)) { ALOGE('failed to read command ') break } buf[count] = 0 // execute commands sent by the client if (execute(s, buf)) break } // End of the request to execute the client, closes the socket connection, proceed to receive the request mode ALOGI('closing connection ') close(s) } return 0 }この関数は、最初にいくつかの変数インストールディレクトリを初期化し、次に環境変数からハンドル値インストールキットワードを取得し、クライアント要求によって送信されると、このソケットをモニターに取り込み、クライアント要求を受信します。コマンドデータで送信されたクライアントを読み取り、読み取りコマンドクライアントに従ってコマンド操作を実行します。

1)変数の初期化

int initialize_globals() { // read data stored in the directory from the environment variable, configure the ANDROID_DATA in the Android startup script init.rc // environment variable, export ANDROID_DATA / data, so the variable android_data_dir = / data / if (get_path_from_env(&android_data_dir, 'ANDROID_DATA') <0) { return -1 } // get application installation directory android_app_dir = / data / app / if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) { return -1 } // get private application directory android_app_private_dir = / data / app-private / if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) { return -1 } // get the mount point sd-card ASEC from an environment variable in the startup script is also configured init.rc: export ASEC_MOUNTPOINT / mnt / asec // Thus android_asec_dir = / mnt / asec / if (get_path_from_env(&android_asec_dir, 'ASEC_MOUNTPOINT') < 0) { return -1 } // define variables and allocate storage space android_system_dirs android_system_dirs.count = 2 android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t)) if (android_system_dirs.dirs == NULL) { ALOGE('Couldn't allocate array for dirs aborting ') return -1 } // Get the root android from the environment variable in the startup script is also configured init.rc: export ANDROID_ROOT / system // Thus android_system_dirs.dirs [0] = / system / if (get_path_from_env(&android_system_dirs.dirs[0], 'ANDROID_ROOT') < 0) { free_globals() return -1 } //android_system_dirs.dirs[0]=/system/app/ char *system_app_path = build_string2(android_system_dirs.dirs[0].path, APP_SUBDIR) android_system_dirs.dirs[0].path = system_app_path android_system_dirs.dirs[0].len = strlen(system_app_path) android_app_preload_dir.path = '/system/preloadapp/' android_app_preload_dir.len = strlen(android_app_preload_dir.path) android_system_dirs.dirs[1].path = '/vendor/app/' android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path) return 0 }

2)ディレクトリを初期化する

int initialize_directories() { // user_data_dir=/data/user char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX) // legacy_data_dir=/data/data char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX) // primary_data_dir=/data/user/0 char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, '0') int ret = -1 if (user_data_dir != NULL && primary_data_dir != NULL && legacy_data_dir != NULL) { ret = 0 // If the / data / user directory does not exist, create it if (access(user_data_dir, R_OK) <0) { if (mkdir(user_data_dir, 0711) < 0) { return -1 } // modify directory permissions and all properties if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) { return -1 } if (chmod(user_data_dir, 0711) < 0) { return -1 } } // Make the /data/user/0 symlink to /data/data if necessary if (access(primary_data_dir, R_OK) < 0) { ret = symlink(legacy_data_dir, primary_data_dir) } free(user_data_dir) free(legacy_data_dir) free(primary_data_dir) } return ret }

3)クライアントから送信された実行要求コマンド

static int execute(int s, char cmd[BUFFER_MAX]) { //#define BUFFER_MAX 1024 /* input buffer for commands */ char reply[REPLY_MAX] //#define REPLY_MAX 256 /* largest reply allowed */ char * arg [TOKEN_MAX + 1] // # define TOKEN_MAX 8 / * command parameters up to 8 * / unsigned i unsigned n = 0 unsigned short count int ret = -1 reply[0] = 0 // arg [0] is the name of the command, the command format: [name arg1 arg2 arg3 arg4] arg[0] = cmd // count the number of command parameters while (*cmd) { if (isspace(*cmd)) { *cmd++ = 0 n++ arg[n] = cmd if (n == TOKEN_MAX) { ALOGE('too many arguments ') goto done } } cmd++ } // command according to the command name matches an array of command cmds for (i = 0 i BUFFER_MAX) n = BUFFER_MAX // Returns the data length count = n // write the resulting data length if (writex(s, &count, sizeof(count))) return -1 // write the result data if (writex(s, cmd, count)) return -1 return 0 }

4)installdservice実行可能コマンド

struct cmdinfo cmds[] = { {// command name, number of parameters, the command execution function} { 'ping', 0, do_ping }, { 'install', 3, do_install }, { 'dexopt', 3, do_dexopt }, { 'movedex', 2, do_move_dex }, { 'rmdex', 1, do_rm_dex }, { 'remove', 2, do_remove }, { 'rename', 2, do_rename }, { 'fixuid', 3, do_fixuid }, { 'freecache', 1, do_free_cache }, { 'rmcache', 1, do_rm_cache }, { 'protect', 2, do_protect }, { 'getsize', 4, do_get_size }, { 'rmuserdata', 2, do_rm_user_data }, { 'movefiles', 0, do_movefiles }, { 'linklib', 2, do_linklib }, { 'unlinklib', 1, do_unlinklib }, { 'mkuserdata', 3, do_mk_user_data }, { 'rmuser', 1, do_rm_user }, { 'cloneuserdata', 3, do_clone_user_data }, }

5)アプリケーションのインストール

static int do_install(char **arg, char reply[REPLY_MAX]) { return install(arg[0], atoi(arg[1]), atoi(arg[2])) /* pkgname, uid, gid */ }フレームワーク base cmds installd commands.cを直接呼び出してインストール関数をインストールしますint install(const char *pkgname, uid_t uid, gid_t gid) { char pkgdir [PKG_PATH_MAX] // program directory path up to 256 char libdir [PKG_PATH_MAX] // lib path program up to 256 // permission judgment if ((uid 構成アプリケーションのインストールディレクトリパス:int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname, const char *postfix, uid_t persona) { size_t uid_len char* persona_prefix //postfix='' //persona=0 if (persona == 0) { persona_prefix = PRIMARY_USER_PREFIX// 'data/' uid_len = 0 } else { persona_prefix = SECONDARY_USER_PREFIX// 'user/' uid_len = snprintf(NULL, 0, '%d', persona) } // /data/data/ const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/ char prefix[prefix_len + 1] char *dst = prefix size_t dst_size = sizeof(prefix) //dst=/data/data/ if (append_and_increment(&dst, android_data_dir.path, &dst_size) <0 || append_and_increment(&dst, persona_prefix, &dst_size) < 0) { ALOGE('Error building prefix for APK path') return -1 } if (persona != 0) { int ret = snprintf(dst, dst_size, '%d/', persona) if (ret PKG_NAME_MAX) { return -1 } // Check whether the package name naming specification if (is_valid_package_name(pkgname) len + postfix_len)>= PKG_PATH_MAX) { return -1 } char *dst = path size_t dst_size = PKG_PATH_MAX // final installation directory is / data / data / application package name / postfix if (append_and_increment(&dst, dir->path, &dst_size) <0 || append_and_increment(&dst, pkgname, &dst_size) < 0 || append_and_increment(&dst, postfix, &dst_size) < 0) { ALOGE('Error building APK path') return -1 } return 0 }

6)アプリケーションのアンインストール

アプリケーションのアンインストールプロセスは、実際にはアプリケーションのインストールファイルを削除することですstatic int do_remove(char **arg, char reply[REPLY_MAX]) { return uninstall(arg[0], atoi(arg[1])) /* pkgname, userid */ } int uninstall(const char *pkgname, uid_t persona) { char pkgdir[PKG_PATH_MAX] // get the application installation directory path according to the package name if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) return -1 / * File * delete the installation directory and in the directory / return delete_dir_contents(pkgdir, 1, NULL) } int delete_dir_contents(const char *pathname, int also_delete_dir, const char *ignore) { int res = 0 DIR *d // open the application installation directory d = opendir(pathname) if (d == NULL) { ALOGE('Couldn't opendir %s: %s ', pathname, strerror(errno)) return -errno } // delete the files in the installation directory res = _delete_dir_contents(d, ignore) closedir(d) // delete the installation directory if (also_delete_dir) { if (rmdir(pathname)) { ALOGE('Couldn't rmdir %s: %s ', pathname, strerror(errno)) res = -1 } } return res }

7)アプリケーションインストールパッケージの最適化プロセス

static int do_dexopt(char **arg, char reply[REPLY_MAX]) { return dexopt(arg[0], atoi(arg[1]), atoi(arg[2])) /* apk_path, uid, is_public */ } apkファイルの最適化を実行するためのDexopt直接呼び出し関数int dexopt(const char *apk_path, uid_t uid, int is_public) { // For example: apk_path = system / app / Music.apk struct utimbuf ut struct stat apk_stat, dex_stat char dex_path[PKG_PATH_MAX]//PKG_PATH_MAX=256 char dexopt_flags[PROPERTY_VALUE_MAX]//PKG_PATH_MAX=92 char *end int res, zip_fd=-1, odex_fd=-1 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { return -1 } // Read the installation package optimization flag property_get('dalvik.vm.dexopt-flags', dexopt_flags, '') //dex_path=system/app/Music.apk strcpy(dex_path, apk_path) // determine the suffix dex_path end = strrchr(dex_path, '.') if (end != NULL) { strcpy(end, '.odex') if (stat(dex_path, &dex_stat) == 0) { return 0 } } //dex_path=/data/dalvik-cache/[root@[email protected]]@classes.dex if (create_cache_path(dex_path, apk_path)) { return -1 } memset(&apk_stat, 0, sizeof(apk_stat)) // Get the apk file information stat(apk_path, &apk_stat) // Open the apk file read-only zip_fd = open(apk_path, O_RDONLY, 0) if (zip_fd <0) { ALOGE('dexopt cannot open '%s' for input ', apk_path) return -1 } // delete files dex unlink(dex_path) // Open dex file, if the file does not exist, the file is automatically created odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644) if (odex_fd < 0) { ALOGE('dexopt cannot open '%s' for output ', dex_path) goto fail } // modify the property owner dex file if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { ALOGE('dexopt cannot chown '%s' ', dex_path) goto fail } // modify permissions dex file if (fchmod(odex_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) <0) { ALOGE('dexopt cannot chmod '%s' ', dex_path) goto fail } ALOGV('DexInv: --- BEGIN '%s' --- ', apk_path) pid_t pid // create a thread to perform optimization apk pid = fork() if (pid == 0) { if (setgid(uid) != 0) { ALOGE('setgid(%d) failed during dexopt ', uid) exit(64) } if (setuid(uid) != 0) { ALOGE('setuid(%d) during dexopt ', uid) exit(65) } if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE('flock(%s) failed: %s ', dex_path, strerror(errno)) exit(66) } // Optimization Pack apk file, zip_fd for the apk file handles, odex_fd for the dex file handles, dexopt_flags for the optimization flag run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags) exit(67) /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path) if (res != 0) { ALOGE('dexopt failed on '%s' res = %d ', dex_path, res) goto fail } } ut.actime = apk_stat.st_atime ut.modtime = apk_stat.st_mtime utime(dex_path, &ut) close(odex_fd) close(zip_fd) return 0 fail: if (odex_fd>= 0) { close(odex_fd) unlink(dex_path) } if (zip_fd >= 0) { close(zip_fd) } return -1 }インストールパッケージの最適化タスクを実行するための新しいスレッドを作成しますstatic void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name, const char* dexopt_flags) { // input_file_name path for the apk static const char* DEX_OPT_BIN = '/system/bin/dexopt' static const int MAX_INT_LEN = 12 char zip_num[MAX_INT_LEN] char odex_num[MAX_INT_LEN] sprintf (zip_num, '% d', zip_fd) // apk file handle sprintf (odex_num, '% d', odex_fd) // dex file handle // Call / system / bin / dexopt tool to optimize the apk file execl(DEX_OPT_BIN, DEX_OPT_BIN, '--zip', zip_num, odex_num, input_file_name, dexopt_flags, (char*) NULL) ALOGE('execl(%s) failed: %s ', DEX_OPT_BIN, strerror(errno)) }最適化プロセスは、システムディレクトリのdexoptツールによって実行されます。ここでは、このツールを直接使用して、apkの最適化を完了します。 / data / dalvik-cache /ディレクトリにあるdex最適化ファイル: