Android应用安装过程分析(二)
来源:互联网 发布:易店淘宝店铺买卖骗局 编辑:程序博客网 时间:2024/05/17 00:11
上次说到initView的两句核心代码,installPackageWithVerificationAndEncryption函数和installExistingPackage函数。
而成员pm是一个PackageManager类型的变量,这是一个接口类,具体的实现代码在PackageManagerService中
public void installPackageWithVerificationAndEncryption(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); final int uid = Binder.getCallingUid(); if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) { try { observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED); } catch (RemoteException re) { } return; } UserHandle user; if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) { user = UserHandle.ALL; } else { user = new UserHandle(UserHandle.getUserId(uid)); } final int filteredFlags; if (uid == Process.SHELL_UID || uid == 0) { if (DEBUG_INSTALL) { Slog.v(TAG, "Install from ADB"); } filteredFlags = flags | PackageManager.INSTALL_FROM_ADB; } else { filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB; } verificationParams.setInstallerUid(uid); final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, verificationParams, encryptionParams, user); mHandler.sendMessage(msg); }
在Android中,PackageManager负责管理安装包的信息,但是应用的安装和卸载是PackageManager访问installd服务来获得
int res = mInstaller.install(packageName, uid, uid, seinfo);这是PackageManager中的代码
mInstaller来自Installer
public int install(String name, int uid, int gid, String seinfo) { StringBuilder builder = new StringBuilder("install"); builder.append(' '); builder.append(name); builder.append(' '); builder.append(uid); builder.append(' '); builder.append(gid); builder.append(' '); builder.append(seinfo != null ? seinfo : "!"); return execute(builder.toString()); }install中调用execute
private int execute(String cmd) { String res = transaction(cmd); try { return Integer.parseInt(res); } catch (NumberFormatException ex) { return -1; } }再调用transaction
private synchronized String transaction(String cmd) { if (!connect()) { Slog.e(TAG, "connection failed"); return "-1"; } if (!writeCommand(cmd)) { /* * If installd died and restarted in the background (unlikely but * possible) we'll fail on the next write (this one). Try to * reconnect and write the command one more time before giving up. */ Slog.e(TAG, "write command failed? reconnect!"); if (!connect() || !writeCommand(cmd)) { return "-1"; } } if (LOCAL_DEBUG) { Slog.i(TAG, "send: '" + cmd + "'"); } if (readReply()) { String s = new String(buf, 0, buflen); if (LOCAL_DEBUG) { Slog.i(TAG, "recv: '" + s + "'"); } return s; } else { if (LOCAL_DEBUG) { Slog.i(TAG, "fail"); } return "-1"; } }可以看到首先通过connect函数进行连接
private boolean connect() { if (mSocket != null) { return true; } Slog.i(TAG, "connecting..."); try { mSocket = new LocalSocket(); LocalSocketAddress address = new LocalSocketAddress("installd", LocalSocketAddress.Namespace.RESERVED); mSocket.connect(address); mIn = mSocket.getInputStream(); mOut = mSocket.getOutputStream(); } catch (IOException ex) { disconnect(); return false; } return true; }
address指向的就是install服务,通过LocalSocket本地套接字。此外还有输入输出流
public final class Installer { private static final String TAG = "Installer"; private static final boolean LOCAL_DEBUG = false; InputStream mIn; OutputStream mOut; LocalSocket mSocket; byte buf[] = new byte[1024]; int buflen = 0;connect连接成功后使用writeCommand函数将内容写入通信流当中
private boolean writeCommand(String _cmd) { byte[] cmd = _cmd.getBytes(); int len = cmd.length; if ((len < 1) || (len > 1024)) return false; buf[0] = (byte) (len & 0xff); buf[1] = (byte) ((len >> 8) & 0xff); try { mOut.write(buf, 0, 2); mOut.write(cmd, 0, len); } catch (IOException ex) { Slog.e(TAG, "write error"); disconnect(); return false; } return true; }脉络很清楚pm ——> PackageManagerServer ——> Installer.install ——>通过LocalSocket ——> Installd
相关文件位置
frameworks\native\cmds\installd\installd.c
frameworks\base\services\java\com\android\server\pm\PackageManagerService.java
frameworks\base\services\java\com\android\server\pm\Installer.java
下面着重关注一下installd
主函数
int main(const int argc, const char *argv[]) { char buf[BUFFER_MAX]; struct sockaddr addr; socklen_t alen; int lsocket, s, count; ALOGI("installd firing up\n"); if (initialize_globals() < 0) {//初始化全局变量 ALOGE("Could not initialize globals; exiting.\n"); exit(1); } if (initialize_directories() < 0) {//初始化安装目录 ALOGE("Could not create directories; exiting.\n"); exit(1); } drop_privileges();//权限限制 lsocket = android_get_control_socket(SOCKET_PATH);//取得套接字句柄 if (lsocket < 0) { ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); exit(1); } if (listen(lsocket, 5)) {//监听socket ALOGE("Listen on socket failed: %s\n", strerror(errno)); exit(1); } fcntl(lsocket, F_SETFD, FD_CLOEXEC);//修改socket的属性 for (;;) {//循环等待客户端的消息 alen = sizeof(addr); s = accept(lsocket, &addr, &alen); if (s < 0) { ALOGE("Accept failed: %s\n", strerror(errno)); continue; } fcntl(s, F_SETFD, FD_CLOEXEC); ALOGI("new connection\n"); for (;;) {//循环读取内容 unsigned short count; //客户端数据的格式为 | 数据长度 | 数据内容 | //读取头四个字节获得长度 if (readx(s, &count, sizeof(count))) { ALOGE("failed to read size\n"); break; } //判断长度的合法性 if ((count < 1) || (count >= BUFFER_MAX)) { ALOGE("invalid size %d\n", count); break; } //读取全部内容 if (readx(s, buf, count)) { ALOGE("failed to read command\n"); break; } //执行 buf[count] = 0; if (execute(s, buf)) break; } ALOGI("closing connection\n"); close(s); } return 0;}全局变量的初始化函数initialize_globals
int initialize_globals() { // Get the android data directory. if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) { return -1; } // Get the android app directory. if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) { return -1; } // Get the android protected app directory. if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) { return -1; } // Get the android app native library directory. if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) { return -1; } // Get the sd-card ASEC mount point. if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) { return -1; } // Get the android media directory. if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) { return -1; } // Take note of the system and vendor directories. 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\n"); return -1; } // system if (get_path_from_env(&android_system_dirs.dirs[0], "ANDROID_ROOT") < 0) { free_globals(); return -1; } // append "app/" to dirs[0] 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); // vendor // TODO replace this with an environment variable (doesn't exist yet) android_system_dirs.dirs[1].path = "/vendor/app/"; android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path); return 0;}全局变量位于同目录下的installd.h文件,部分变量如下所示
typedef struct { char* path; size_t len;} dir_rec_t;typedef struct { size_t count; dir_rec_t* dirs;} dir_rec_array_t;extern dir_rec_t android_app_dir;extern dir_rec_t android_app_private_dir;extern dir_rec_t android_app_lib_dir;extern dir_rec_t android_data_dir;extern dir_rec_t android_asec_dir;extern dir_rec_t android_media_dir;extern dir_rec_array_t android_system_dirs;此外这当中的一些函数比如copy_and_append,也位于同目录下的utils.c
int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) { dst->len = src->len + strlen(suffix); const size_t dstSize = dst->len + 1; dst->path = (char*) malloc(dstSize); if (dst->path == NULL || snprintf(dst->path, dstSize, "%s%s", src->path, suffix) != (ssize_t) dst->len) { ALOGE("Could not allocate memory to hold appended path; aborting\n"); return -1; } return 0;}之后是初始化安装目录initialize_directories
int initialize_directories() { int res = -1; // Read current filesystem layout version to handle upgrade paths char version_path[PATH_MAX]; snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path); int oldVersion; if (fs_read_atomic_int(version_path, &oldVersion) == -1) { oldVersion = 0; } int version = oldVersion; // /data/user char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX); // /data/data char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX); // /data/user/0 char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0"); if (!user_data_dir || !legacy_data_dir || !primary_data_dir) { goto fail; } // Make the /data/user directory if necessary if (access(user_data_dir, R_OK) < 0) { if (mkdir(user_data_dir, 0711) < 0) { goto fail; } if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) { goto fail; } if (chmod(user_data_dir, 0711) < 0) { goto fail; } } // Make the /data/user/0 symlink to /data/data if necessary if (access(primary_data_dir, R_OK) < 0) { if (symlink(legacy_data_dir, primary_data_dir)) { goto fail; } } if (version == 0) { // Introducing multi-user, so migrate /data/media contents into /data/media/0 ALOGD("Upgrading /data/media for multi-user"); // Ensure /data/media if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // /data/media.tmp char media_tmp_dir[PATH_MAX]; snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path); // Only copy when upgrade not already in progress if (access(media_tmp_dir, F_OK) == -1) { if (rename(android_media_dir.path, media_tmp_dir) == -1) { ALOGE("Failed to move legacy media path: %s", strerror(errno)); goto fail; } } // Create /data/media again if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // /data/media/0 char owner_media_dir[PATH_MAX]; snprintf(owner_media_dir, PATH_MAX, "%s0", android_media_dir.path); // Move any owner data into place if (access(media_tmp_dir, F_OK) == 0) { if (rename(media_tmp_dir, owner_media_dir) == -1) { ALOGE("Failed to move owner media path: %s", strerror(errno)); goto fail; } } // Ensure media directories for any existing users DIR *dir; struct dirent *dirent; char user_media_dir[PATH_MAX]; dir = opendir(user_data_dir); if (dir != NULL) { while ((dirent = readdir(dir))) { if (dirent->d_type == DT_DIR) { const char *name = dirent->d_name; // skip "." and ".." if (name[0] == '.') { if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } // /data/media/<user_id> snprintf(user_media_dir, PATH_MAX, "%s%s", android_media_dir.path, name); if (fs_prepare_dir(user_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } } } closedir(dir); } version = 1; } // /data/media/obb char media_obb_dir[PATH_MAX]; snprintf(media_obb_dir, PATH_MAX, "%sobb", android_media_dir.path); if (version == 1) { // Introducing /data/media/obb for sharing OBB across users; migrate // any existing OBB files from owner. ALOGD("Upgrading to shared /data/media/obb"); // /data/media/0/Android/obb char owner_obb_path[PATH_MAX]; snprintf(owner_obb_path, PATH_MAX, "%s0/Android/obb", android_media_dir.path); // Only move if target doesn't already exist if (access(media_obb_dir, F_OK) != 0 && access(owner_obb_path, F_OK) == 0) { if (rename(owner_obb_path, media_obb_dir) == -1) { ALOGE("Failed to move OBB from owner: %s", strerror(errno)); goto fail; } } version = 2; } if (ensure_media_user_dirs(0) == -1) { ALOGE("Failed to setup media for user 0"); goto fail; } if (fs_prepare_dir(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { goto fail; } // Persist layout version if changed if (version != oldVersion) { if (fs_write_atomic_int(version_path, version) == -1) { ALOGE("Failed to save version to %s: %s", version_path, strerror(errno)); goto fail; } } // Success! res = 0;fail: free(user_data_dir); free(legacy_data_dir); free(primary_data_dir); return res;}然后drop_privileges,用于设置权限
static void drop_privileges() { if (prctl(PR_SET_KEEPCAPS, 1) < 0) { ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); exit(1); } if (setgid(AID_INSTALL) < 0) { ALOGE("setgid() can't drop privileges; exiting.\n"); exit(1); } if (setuid(AID_INSTALL) < 0) { ALOGE("setuid() can't drop privileges; exiting.\n"); exit(1); } struct __user_cap_header_struct capheader; struct __user_cap_data_struct capdata[2]; memset(&capheader, 0, sizeof(capheader)); memset(&capdata, 0, sizeof(capdata)); capheader.version = _LINUX_CAPABILITY_VERSION_3; capheader.pid = 0; capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE); capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN); capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); capdata[0].effective = capdata[0].permitted; capdata[1].effective = capdata[1].permitted; capdata[0].inheritable = 0; capdata[1].inheritable = 0; if (capset(&capheader, &capdata[0]) < 0) { ALOGE("capset failed: %s\n", strerror(errno)); exit(1); }}这当中包含了gid和uid的设定
执行函数execute
static int execute(int s, char cmd[BUFFER_MAX]){ char reply[REPLY_MAX]; char *arg[TOKEN_MAX+1]; unsigned i; unsigned n = 0; unsigned short count; int ret = -1;// ALOGI("execute('%s')\n", cmd); /* default reply is "" */ reply[0] = 0; /* n is number of args (not counting arg[0]) */ arg[0] = cmd; while (*cmd) { if (isspace(*cmd)) { *cmd++ = 0; n++; arg[n] = cmd; if (n == TOKEN_MAX) { ALOGE("too many arguments\n"); goto done; } } cmd++; } //与cmds中保存的命令进行匹配,并且要检查参数个数是否符合要求 for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { if (!strcmp(cmds[i].name,arg[0])) { if (n != cmds[i].numargs) { ALOGE("%s requires %d arguments (%d given)\n", cmds[i].name, cmds[i].numargs, n); } else { ret = cmds[i].func(arg + 1, reply); } goto done; } } ALOGE("unsupported command '%s'\n", arg[0]);done: if (reply[0]) { n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply); } else { n = snprintf(cmd, BUFFER_MAX, "%d", ret); } if (n > BUFFER_MAX) n = BUFFER_MAX; count = n;// ALOGI("reply: '%s'\n", cmd); if (writex(s, &count, sizeof(count))) return -1; if (writex(s, cmd, count)) return -1; return 0;}函数很简单。。。
cmds的内容
struct cmdinfo cmds[] = { { "ping", 0, do_ping }, { "install", 4, 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", 2, do_rm_cache }, { "getsize", 6, do_get_size }, { "rmuserdata", 2, do_rm_user_data }, { "movefiles", 0, do_movefiles }, { "linklib", 3, do_linklib }, { "mkuserdata", 3, do_mk_user_data }, { "rmuser", 1, do_rm_user },};第一列是命令字符串,第二列是该命令的参数个数,第三列是函数指针。
cmdinfo结构
struct cmdinfo { const char *name; unsigned numargs; int (*func)(char **arg, char reply[REPLY_MAX]);};
这些do开头的函数只是对真正执行函数的一个简单封装,比如do_install
static int do_install(char **arg, char reply[REPLY_MAX]){ return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */}而真正的执行函数都保存在同目录下的commands.c文件中
int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo){ char pkgdir[PKG_PATH_MAX]; char libsymlink[PKG_PATH_MAX]; char applibdir[PKG_PATH_MAX]; struct stat libStat; if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { ALOGE("invalid uid/gid: %d %d\n", uid, gid); return -1; } if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) { ALOGE("cannot create package path\n"); return -1; } if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, 0)) { ALOGE("cannot create package lib symlink origin path\n"); return -1; } if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) { ALOGE("cannot create package lib symlink dest path\n"); return -1; } if (mkdir(pkgdir, 0751) < 0) { ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); return -1; } if (chmod(pkgdir, 0751) < 0) { ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); unlink(pkgdir); return -1; } if (lstat(libsymlink, &libStat) < 0) { if (errno != ENOENT) { ALOGE("couldn't stat lib dir: %s\n", strerror(errno)); return -1; } } else { if (S_ISDIR(libStat.st_mode)) { if (delete_dir_contents(libsymlink, 1, 0) < 0) { ALOGE("couldn't delete lib directory during install for: %s", libsymlink); return -1; } } else if (S_ISLNK(libStat.st_mode)) { if (unlink(libsymlink) < 0) { ALOGE("couldn't unlink lib directory during install for: %s", libsymlink); return -1; } } } if (symlink(applibdir, libsymlink) < 0) { ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir, strerror(errno)); unlink(pkgdir); return -1; } if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) { ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); unlink(libsymlink); unlink(pkgdir); return -errno; } if (chown(pkgdir, uid, gid) < 0) { ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); unlink(libsymlink); unlink(pkgdir); return -1; } return 0;}
0 0
- Android应用安装过程分析(二)
- Android应用安装过程分析(一)
- Android 应用安装过程分析
- android(二)、 应用启动过程
- Android 应用安装过程
- Android应用安装过程
- 【android】应用程序安装过程分析(二)——————系统正常运行时的安装过程
- Android 启动过程分析 (二)
- Android应用优化过程分析
- Android应用的安装过程
- Android Apk安装过程分析
- 【Android App】Calculator(二)计算过程详细分析
- Android启动过程分析——init.c(二)
- 对android应用安装程序apk反编译与分析(二)-jad将class文件转化为java文件
- Android init 启动过程分析(二)
- Android应用程序包扫描过程源码分析
- Android应用程序包扫描过程源码分析
- Android应用程序包扫描过程源码分析
- Hdu oj 1014 Uniform Generator(水题)
- Hadoop分布式环境搭建
- 依次把 11 个关键字插入到初始化为空的平衡二叉排序树中,在插入过程中平衡树条件如被破坏,得到的平衡二叉排序树的深度为()
- MySQL学习笔记三
- 把静态编译的QT添加到QTCreator当中创建新工程
- Android应用安装过程分析(二)
- Ajax请求Servlet返回文本 json html和XML数据并解析xml及responseText和responseXML的区别
- tjut 5396
- 下列哪个IP地址可以分配给一台计算机?
- NOIP2016#模拟考试 Day.1# T1 洗澡
- hdoj-1973-Prime Path
- 【C#】const和readonly的区别
- group_concat函数详解
- ARM Cortex-M Series Processors