Android N installd与PackageManagerService
2017-11-22 18:07
381 查看
Android系统中应用的安装卸载都是通过调用PackageManagerService来完成的,但在PKMS中,对于目录的创建、文件copy、dex优化都是通过调用底层的installd来完成的。至于为什么不直接在PKMS中进行文件的操作,主要是涉及到权限的问题,PKMS只有system的权限,而installd的作用就是处理需要root权限的操作。
1. installd启动
Instlld进程是init.rc中被启动的
service installd
/system/bin/installd
class main
socket installd stream 600 system system
class main表示执行installd.cpp的main函数
socket installd stream 600 system system表示在/dev/socket/下创建一个unix domain的socket,并传递创建的文件描述符fd给服务进程.其中type为stream,权限600,用户名和用户组都是system
下面分析installd.cpp的main函数
Installd作为socket服务端,监听java层的连接并执行java层的命令
2.installer服务启动
installer服务启动
Installer是java层服务,作为client负责和底层installd进行通信,其在SystemServer中被启动。
SystemServerManager启动服务,通过反射获取system service的实例,加入内部变量mService中,然后调用service的onstart()方法。
Installer构造函数和onStart()如下:
waitForConnection()函数如下:
向底层发了ping操作的命令,具体执行流程如下,同时也是其他操作向底层installd通信的流程
首先是execute()函数,如下:
下面具体看transact()方法
transact()方法有几个主要的方法:
1.connect(),首先会判断instller是否和底层installd建立了连接,建立连接只需要执行一次
2.writeCommand(),往instlld发送信息
3.readReply()读取instlld返回的信息
先分析connect()
writeCommand()如下:
readReply()如下:
到这,java层已经建立了和installd的连接,请求流程也做了分析。
SystemServer启动PackageManagerService时,会传入Installer对象,当PackageManagerService安装卸载应用时,就会最终调用到InstallerConnection的execute向instlld发送命令。
3.Installd处理流程
前面分析过,在installd.cpp中创建了一个循环,连接到client后,调用用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
= cmd;
if (n == TOKEN_MAX) {
ALOGE("too many arguments\n");
goto done;
}
}
if (*cmd) {
cmd++;
}
}
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;
}通过解析传入的信息,调用相应的函数,instlld所有的命令如下。
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
{ "create_app_data", 7, do_create_app_data },
{ "restorecon_app_data", 6, do_restorecon_app_data },
{ "migrate_app_data", 4, do_migrate_app_data },
{ "clear_app_data", 5, do_clear_app_data },
{ "destroy_app_data", 5, do_destroy_app_data },
{ "move_complete_
9017
app", 7, do_move_complete_app },
{ "get_app_size", 6, do_get_app_size },
{ "get_app_data_inode", 4, do_get_app_data_inode },
{ "create_user_data", 4, do_create_user_data },
{ "destroy_user_data", 3, do_destroy_user_data },
{ "dexopt", 10, do_dexopt },
{ "markbootcomplete", 1, do_mark_boot_complete },
{ "rmdex", 2, do_rm_dex },
{ "freecache", 2, do_free_cache },
{ "linklib", 4, do_linklib },
{ "idmap", 3, do_idmap },
{ "createoatdir", 2, do_create_oat_dir },
{ "rmpackagedir", 1, do_rm_package_dir },
{ "clear_app_profiles", 1, do_clear_app_profiles },
{ "destroy_app_profiles", 1, do_destroy_app_profiles },
{ "linkfile", 3, do_link_file },
{ "move_ab", 3, do_move_ab },
{ "merge_profiles", 2, do_merge_profiles },
{ "dump_profiles", 3, do_dump_profiles },
};
1. installd启动
Instlld进程是init.rc中被启动的
service installd
/system/bin/installd
class main
socket installd stream 600 system system
class main表示执行installd.cpp的main函数
socket installd stream 600 system system表示在/dev/socket/下创建一个unix domain的socket,并传递创建的文件描述符fd给服务进程.其中type为stream,权限600,用户名和用户组都是system
下面分析installd.cpp的main函数
static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) { char buf[BUFFER_MAX]; struct sockaddr addr; socklen_t alen; int lsocket, s; int selinux_enabled = (is_selinux_enabled() > 0); setenv("ANDROID_LOG_TAGS", "*:v", 1); android::base::InitLogging(argv); ALOGI("installd firing up\n"); union selinux_callback cb; cb.func_log = log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); if (!initialize_globals()) { ALOGE("Could not initialize globals; exiting.\n"); exit(1); } if (initialize_directories() < 0) { ALOGE("Could not create directories; exiting.\n"); exit(1); } if (selinux_enabled && selinux_status_open(true) < 0) { ALOGE("Could not open selinux status; exiting.\n"); exit(1); } //从dev/socket下获取名为installd的socket,该socket在init阶段创建 lsocket = android_get_control_socket(SOCKET_PATH); if (lsocket < 0) { ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); exit(1); } //监听socket,最大连接数为5 if (listen(lsocket, 5)) { ALOGE("Listen on socket failed: %s\n", strerror(errno)); exit(1); } fcntl(lsocket, F_SETFD, FD_CLOEXEC); for (;;) { alen = sizeof(addr); //接受来自java层的连接 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 (selinux_enabled && selinux_status_updated() > 0) { selinux_android_seapp_context_reload(); } //执行命令 if (execute(s, buf)) break; } ALOGI("closing connection\n"); close(s); } return 0; }
Installd作为socket服务端,监听java层的连接并执行java层的命令
2.installer服务启动
installer服务启动
Installer是java层服务,作为client负责和底层installd进行通信,其在SystemServer中被启动。
private void startBootstrapServices() { // Wait for installd to finish starting up so that it has a chance to // create critical directories such as /data/user with the appropriate // permissions. We need this to complete before we initialize other services. Installer installer = mSystemServiceManager.startService(Installer.class); ...... }
public <T extends SystemService> T startService(Class<T> serviceClass) { try { final String name = serviceClass.getName(); Slog.i(TAG, "Starting " + name); Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name); // Create the service. if (!SystemService.class.isAssignableFrom(serviceClass)) { throw new RuntimeException("Failed to create " + name + ": service must extend " + SystemService.class.getName()); } final T service; try { Constructor<T> constructor = serviceClass.getConstructor(Context.class); service = constructor.newInstance(mContext); } catch (InstantiationException ex) { throw new RuntimeException("Failed to create service " + name + ": service could not be instantiated", ex); } catch (IllegalAccessException ex) { throw new RuntimeException("Failed to create service " + name + ": service must have a public constructor with a Context argument", ex); } catch (NoSuchMethodException ex) { throw new RuntimeException("Failed to create service " + name + ": service must have a public constructor with a Context argument", ex); } catch (InvocationTargetException ex) { throw new RuntimeException("Failed to create service " + name + ": service constructor threw an exception", ex); } // Register it. mServices.add(service); // Start it. try { service.onStart(); } catch (RuntimeException ex) { throw new RuntimeException("Failed to start service " + name + ": onStart threw an exception", ex); } return service; } finally { Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); } }
SystemServerManager启动服务,通过反射获取system service的实例,加入内部变量mService中,然后调用service的onstart()方法。
Installer构造函数和onStart()如下:
public Installer(Context context) { super(context); mInstaller = new InstallerConnection(); }
@Override public void onStart() { Slog.i(TAG, "Waiting for installd to be ready."); mInstaller.waitForConnection(); }在Intaller构造函数中new了一个InstallerConnection对象,并在onStart()中调用InstallerConnection的waitForConnection()方法。
waitForConnection()函数如下:
public void waitForConnection() { for (;;) { try { execute("ping"); return; } catch (InstallerException ignored) { } Slog.w(TAG, "installd not ready"); SystemClock.sleep(1000); } }
向底层发了ping操作的命令,具体执行流程如下,同时也是其他操作向底层installd通信的流程
首先是execute()函数,如下:
public String[] execute(String cmd, Object... args) throws InstallerException { final StringBuilder builder = new StringBuilder(cmd); for (Object arg : args) { String escaped; if (arg == null) { escaped = ""; } else { escaped = String.valueOf(arg); } if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) { throw new InstallerException( "Invalid argument while executing " + cmd + " " + Arrays.toString(args)); } if (TextUtils.isEmpty(escaped)) { escaped = "!"; } builder.append(' ').append(escaped); } final String[] resRaw = transact(builder.toString()).split(" "); int res = -1; try { res = Integer.parseInt(resRaw[0]); } catch (ArrayIndexOutOfBoundsException | NumberFormatException ignored) { } if (res != 0) { throw new InstallerException( "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res); } return resRaw; }execute()方法首先对参数进行格式处理,然后调用transact(),返回结果保存在resRaw中,若resRaw[0]不为0,则表示执行命令失败。
下面具体看transact()方法
public synchronized String transact(String cmd) { if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); } //与底层installd socket建立连接,只需连接一次 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 + "'"); } //获取返回值 final int replyLength = readReply(); if (replyLength > 0) { String s = new String(buf, 0, replyLength); if (LOCAL_DEBUG) { Slog.i(TAG, "recv: '" + s + "'"); } return s; } else { if (LOCAL_DEBUG) { Slog.i(TAG, "fail"); } return "-1"; } }
transact()方法有几个主要的方法:
1.connect(),首先会判断instller是否和底层installd建立了连接,建立连接只需要执行一次
2.writeCommand(),往instlld发送信息
3.readReply()读取instlld返回的信息
先分析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; }标准的socket方式的连接请求
writeCommand()如下:
private boolean writeCommand(String cmdString) { final byte[] cmd = cmdString.getBytes(); final int len = cmd.length; if ((len < 1) || (len > buf.length)) { 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; }向installd发送消息,先发送连个字节的命令长度,然后在发送命令字符串
readReply()如下:
private int readReply() { if (!readFully(buf, 2)) { return -1; } final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8); if ((len < 1) || (len > buf.length)) { Slog.e(TAG, "invalid reply length (" + len + ")"); disconnect(); return -1; } if (!readFully(buf, len)) { return -1; } return len; }同样获取installd发送的信息,前两个字节存储返回字符串长度,若长度匹配,则读取返回信息,保存在buf中,返回字符串长度。
到这,java层已经建立了和installd的连接,请求流程也做了分析。
SystemServer启动PackageManagerService时,会传入Installer对象,当PackageManagerService安装卸载应用时,就会最终调用到InstallerConnection的execute向instlld发送命令。
3.Installd处理流程
前面分析过,在installd.cpp中创建了一个循环,连接到client后,调用用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
= cmd;
if (n == TOKEN_MAX) {
ALOGE("too many arguments\n");
goto done;
}
}
if (*cmd) {
cmd++;
}
}
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;
}通过解析传入的信息,调用相应的函数,instlld所有的命令如下。
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
{ "create_app_data", 7, do_create_app_data },
{ "restorecon_app_data", 6, do_restorecon_app_data },
{ "migrate_app_data", 4, do_migrate_app_data },
{ "clear_app_data", 5, do_clear_app_data },
{ "destroy_app_data", 5, do_destroy_app_data },
{ "move_complete_
9017
app", 7, do_move_complete_app },
{ "get_app_size", 6, do_get_app_size },
{ "get_app_data_inode", 4, do_get_app_data_inode },
{ "create_user_data", 4, do_create_user_data },
{ "destroy_user_data", 3, do_destroy_user_data },
{ "dexopt", 10, do_dexopt },
{ "markbootcomplete", 1, do_mark_boot_complete },
{ "rmdex", 2, do_rm_dex },
{ "freecache", 2, do_free_cache },
{ "linklib", 4, do_linklib },
{ "idmap", 3, do_idmap },
{ "createoatdir", 2, do_create_oat_dir },
{ "rmpackagedir", 1, do_rm_package_dir },
{ "clear_app_profiles", 1, do_clear_app_profiles },
{ "destroy_app_profiles", 1, do_destroy_app_profiles },
{ "linkfile", 3, do_link_file },
{ "move_ab", 3, do_move_ab },
{ "merge_profiles", 2, do_merge_profiles },
{ "dump_profiles", 3, do_dump_profiles },
};
相关文章推荐
- Android PackageManagerService详细分析
- Android应用程序管理服务启动过程浅析(PackageManagerService)
- Android Fk-PKMS(2) PackageManagerService之应用的安装与卸载
- Android源码之“应用程序界面“分析二(PackageManager和PackageManagerService)
- PackageInstaller 原理简述 & PackageManagerService注记 & PackageParser和AndroidManifest.xml注记 (转)
- Android服务之PackageManagerService启动源码分析
- Android PackageManagerService流程详细分析(七)之监控扫描指定APP目录
- Android8.0 PackageManagerService相关 -- APK安装和install 的变更和源码浅析
- Android PackageManagerService分析二:安装APK
- Android应用框架之PackageManagerService
- PackageInstaller 原理简述 & PackageManagerService注记 & PackageParser和AndroidManifest.xml注记 .
- Android PackageManagerService流程详细分析(三)之PackageHandler
- Android应用管理四 -- APK包的安装、卸载和优化(PackageManagerService)
- Android PackageManagerService流程详细分析(五)之packages
- Android Framework--PackageManagerService
- Android PackageManagerService加载apk流程
- Android M PackageManagerService解析
- Android PackageManagerService详细分析
- Android的软件包管理服务PackageManagerService源码分析
- 【Android源码系列】如何解析APK-PackageManagerService