APK安装流程概述
pre { background: none left top repeat scroll rgba(0, 0, 0, 0); border: 1px solid rgba(0, 0, 0, 1); padding: 0.04cm; direction: ltr; color: rgba(0, 0, 0, 1) }
pre.western { font-family: "Liberation Mono", "Courier New", monospace }
pre.cjk { font-family: "Droid Sans Fallback", "微软雅黑" }
pre.ctl { font-family: "Liberation Mono", "Courier New", monospace }
h3 { direction: ltr }
h3.western { font-family: "Liberation Sans", "Arial", sans-serif; font-weight: normal }
h3.cjk { font-family: "Droid Sans Fallback", "微软雅黑"; font-weight: normal }
h3.ctl { font-family: "Droid Sans Fallback", "微软雅黑" }
h2 { direction: ltr; color: rgba(0, 0, 0, 1) }
h2.western { font-family: "Liberation Sans", "Arial", sans-serif; font-size: 16pt }
h2.cjk { font-family: "Droid Sans Fallback", "微软雅黑"; font-size: 16pt }
h2.ctl { font-family: "Droid Sans Fallback", "微软雅黑"; font-size: 16pt }
p { margin-bottom: 0.25cm; direction: ltr; color: rgba(0, 0, 0, 1); line-height: 120% }
p.western { font-family: "Times New Roman", serif; font-size: 10pt }
p.cjk { font-family: "Times New Roman", serif; font-size: 10pt }
p.ctl { font-family: "Times New Roman", serif; font-size: 10pt }
code.western { font-family: "Liberation Mono", "Courier New", monospace }
code.cjk { font-family: "Droid Sans Fallback", "微软雅黑" }
code.ctl { font-family: "Liberation Mono", "Courier New", monospace }
a:link { text-decoration: none }
一.
APK安装简介
APK为Android
Package的缩写。
Android应用安装有如下四种方式:
1.系统应用安装――开机时完成,没有安装界面;
2.网络下载应用安装――通过market应用完成,没有安装界面;
3.ADB工具安装――没有安装界面;
4.第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。
应用安装涉及到如下几个目录:
- system/app----------------系统自带的应用程序,获得adb
 root权限才能删除;
- data/app-------------------用户程序安装的目录,安装时把apk
 文件复制到此目录;
- data/data-------------------存放应用程序的数据;
- data/dalvik-cache---------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一)。
二.
 系统应用安装
  1.
了解须知:
(1).
对于在/system/app和/data/app目录下的APK文件,在PackageManagerService的启动过程中,会扫描安装。
(2).PackageManagerService由system_server启动,它全面负责应用包的安装,卸载,权限检查等工作。
(3).在每次开机的时
候,PackageManagerService都会在其构造函数中,对指定的目录的APK进行扫描。对于没有安装的APK文件会触发安装过程。
2.
实现原理:
(1).
开机启动PackageManagerService,通过SystemServer.startBootstrapServices()启动。
1 public static PackageManagerService main(Context context, Installer installer,
2 boolean factoryTest, boolean onlyCore) {
3 PackageManagerService m = HwServiceFactory.getHuaweiPackageManagerService(context, installer,
4 factoryTest, onlyCore);
5 ServiceManager.addService("package", m);
6 return m;
7 }
(2). PackageManagerService初始化,执行构造方法,分为六个重要步骤。
第一步:创建Settings对象,添加shareUserId;
1 mSettings = new Settings(mPackages);
2 mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
3 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
4 mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
5 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
6 mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
7 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
8 mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
9 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
10 mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
11 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
12 mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
13 ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
第二步:创建应用安装器Installer,来源是PackageManagerService参数之一。
第三步:构造SystemConfig,读取
”/system/etc/permissions/*.xml”
资源,获取mSystemPermissions(系统权限),mGlobalGids(Group-ids),mAvailableFeatures(系统支持的features)属性。
执行顺序:
com.android.server.pm.PackageManagerService#PackageManagerService
-->
 com.android.server.SystemConfig#getInstance
-->
com.android.server.SystemConfig#SystemConfig
-->
com.android.server.SystemConfig#readPermissions
1 SystemConfig systemConfig = SystemConfig.getInstance();
2 mGlobalGids = systemConfig.getGlobalGids();
3 mSystemPermissions = systemConfig.getSystemPermissions();
4 mAvailableFeatures = systemConfig.getAvailableFeatures();
第四步:创建系统消息处理线程。
1 mHandlerThread = new ServiceThread(TAG,
2 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
3 mHandlerThread.start();
4 mHandler = new PackageHandler(mHandlerThread.getLooper());
5 Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
第五步:执行com.android.server.pm.Settings#readLPw, 读取安装包信息,并解析成对应的数据结构,包括以下重要文件:
- packages.xml:记录系统中所有安装的应用信息,包括基本信息、签名和权限。 
- packages-backup.xml:packages.xml文件的备份。 
- packages.list:保存普通应用的数据目录和uid等信息。 
- packages-stopped.xml:记录系统中被强制停止运行的应用信息。系统在强制停止某个应用时,会讲应用的信息记录到该文件中。 
- packages-stopped-backup.xml:pacakges-stopped.xml文件的备份。 
这几个目录在创建Settings对象的时候,就已经被封装成对应的File文件。
packages-backup.xml是packages.xml的备份文件。在每次写packages.xml文件的时候,都会将旧的 packages.xml文件先备份,这样做是为了防止写文件过程中文件以外损坏,还能从旧的文件中恢复。
package- restrictions.xml保存着受限制的APP的状态,比如某个APP处于disable状态,或者某个APP具有更高的优先级等。
第六步:执行PackageManagerService#scanDirLI。
监控和扫描系统包安装目录:
- /system/framework 系统库
- /system/app 默认的系统应用
- /vendor/app 厂商定制的应用
扫描非系统apk信息:
- /data/app/
- /system/preloadapp/
- /data/app-private/
跟踪扫描安装过程:
①:构建PackageParser对象
 
调用PackageManagerService#scanPackageLI(xxx)
方法。
②:构建一个PackageParser.Package对象并返回
调用PackageParser#parsePackage(java.io.File,
int)
方法,扫描APK安装包的AndroidManifest.xml文件和提取证书信息,以此信息构建一个PackageParser.Package对象,并将其返回;
③:将PackageParser.Package对象的信息保存到PackageManagerService中
其中包括ContentProvider,Activity,Service,BroadcastReceiver;
④:构建PackageSetting
对象
执行以下代码:
.PackageManagerService#scanPackageLI(xxx)
-->
.PackageManagerService#scanPackageDirtyLI
构建PackageSetting
对象,这个对象中保存的信息最后会通过writeLPr写入到/data/system/packages.xml文件中去。
以上几个步骤可以用两个图代替:
----------------------------------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------------------------------------------

⑤:调用mInstaller.createUserData()函数创建数据目录
调用PackageManagerService#createDataDirsLI方法,给installd发送消息,为应用程序创建对应的数据目录,如果已经存在,也会重新创建一遍。
⑥:调用mInstaller.install()函数完成APK安装
 1  private int createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo) {
 2         int[] users = sUserManager.getUserIds();
 3         int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
 4         if (res < 0) {
 5             return res;
 6         }
 7         for (int user : users) {
 8             if (user != 0) {
 9                 res = mInstaller.createUserData(volumeUuid, packageName,
10                         UserHandle.getUid(user, uid), user, seinfo);
11                 if (res < 0) {
12                     return res;
13                 }
14             }
15         }
16         return res;
17     }
Installer.install()函数和createUserData()进行完成了命令组装工作,在组装完命令之后,将命令传递给InstallerConnectio.java处理。
 1 public int install(String uuid, String name, int uid, int gid, String seinfo) {
 2         StringBuilder builder = new StringBuilder("install");
 3         builder.append(' ');
 4         builder.append(escapeNull(uuid));
 5         builder.append(' ');
 6         builder.append(name);
 7         builder.append(' ');
 8         builder.append(uid);
 9         builder.append(' ');
10         builder.append(gid);
11         builder.append(' ');
12         builder.append(seinfo != null ? seinfo : "!");
13         return mInstaller.execute(builder.toString());
14     }
通过分析InstallerConnection.java得到以下结论:
1. InstallerConnection连接一个名为Installd的服务。
2. Install具体的命令有Installd完成。
以下是InstallerConnection连接Installd服务的代码
 1 private boolean connect() {
 2         if (mSocket != null) {
 3             return true;
 4         }
 5         Slog.i(TAG, "connecting...");
 6         try {
 7             mSocket = new LocalSocket();
 8
 9             LocalSocketAddress address = new LocalSocketAddress("installd",
10                     LocalSocketAddress.Namespace.RESERVED);
11
12             mSocket.connect(address);
13
14             mIn = mSocket.getInputStream();
15             mOut = mSocket.getOutputStream();
16         } catch (IOException ex) {
17             disconnect();
18             return false;
19         }
20         return true;
21     }
Installed介绍
Installd是一个native进程,该进程启动一个socket,然后处理来自Installer的命令。
PackageManagerService通过套接字的方式访问installd服务进程,在Android启动脚本init.rc中通过服务配置启动了installd服务进程。
1 service installd /system/bin/installd
2 class main
3 socket installd stream 600 system system
通过以上配置,init进程就会启动installd服务进程了。
Installed
进程的入口是main函数,该函数首先初始化一些变量就安装目录,然后从环境变量中取得installd套件字的句柄值,然后进入监听此socket,当客户端发送过来请求时,接收客户端的请求,并读取客户端发送过来的命令数据,并根据读取的客户端命令来执行命令操作。
1 int main(const int argc __unused, char *argv[]) {
 2     char buf[BUFFER_MAX];
 3     struct sockaddr addr;
 4     socklen_t alen;
 5     int lsocket, s;
 6     int selinux_enabled = (is_selinux_enabled() > 0);
 7
 8     setenv("ANDROID_LOG_TAGS", "*:v", 1);
 9     android::base::InitLogging(argv);
10
11     ALOGI("installd firing up\n");
12
13     union selinux_callback cb;
14     cb.func_log = log_callback;
15     selinux_set_callback(SELINUX_CB_LOG, cb);
16
17     if (initialize_globals() < 0) {
18         ALOGE("Could not initialize globals; exiting.\n");
19         exit(1);
20     }
21
22     if (initialize_directories() < 0) {
23         ALOGE("Could not create directories; exiting.\n");
24         exit(1);
25     }
26
27     if (selinux_enabled && selinux_status_open(true) < 0) {
28         ALOGE("Could not open selinux status; exiting.\n");
29         exit(1);
30     }
31
32     lsocket = android_get_control_socket(SOCKET_PATH);
33     if (lsocket < 0) {
34         ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
35         exit(1);
36     }
37     if (listen(lsocket, 5)) {
38         ALOGE("Listen on socket failed: %s\n", strerror(errno));
39         exit(1);
40     }
41     fcntl(lsocket, F_SETFD, FD_CLOEXEC);
42
43     for (;;) {
44         alen = sizeof(addr);
45         s = accept(lsocket, &addr, &alen);
46         if (s < 0) {
47             ALOGE("Accept failed: %s\n", strerror(errno));
48             continue;
49         }
50         fcntl(s, F_SETFD, FD_CLOEXEC);
51
52         ALOGI("new connection\n");
53         for (;;) {
54             unsigned short count;
55             if (readx(s, &count, sizeof(count))) {
56                 ALOGE("failed to read size\n");
57                 break;
58             }
59             if ((count < 1) || (count >= BUFFER_MAX)) {
60                 ALOGE("invalid size %d\n", count);
61                 break;
62             }
63             if (readx(s, buf, count)) {
64                 ALOGE("failed to read command\n");
65                 break;
66             }
67             buf[count] = 0;
68             if (selinux_enabled && selinux_status_updated() > 0) {
69                 selinux_android_seapp_context_reload();
70             }
71             if (execute(s, buf)) break;
72         }
73         ALOGI("closing connection\n");
74         close(s);
75     }
76
77     return 0;
78 }
main函数调用execute函数,执行客户发送过来的请求命令。
1 static int execute(int s, char cmd[BUFFER_MAX])
2 {
3 char reply[REPLY_MAX];
4 char *arg[TOKEN_MAX+1];
5 unsigned i;
6 unsigned n = 0;
7 unsigned short count;
8 int ret = -1;
9
10 // ALOGI("execute('%s')\n", cmd);
11
12 /* default reply is "" */
13 reply[0] = 0;
14
15 /* n is number of args (not counting arg[0]) */
16 arg[0] = cmd;
17 while (*cmd) {
18 if (isspace(*cmd)) {
19 *cmd++ = 0;
20 n++;
21 arg[n] = cmd;
22 if (n == TOKEN_MAX) {
23 ALOGE("too many arguments\n");
24 goto done;
25 }
26 }
27 if (*cmd) {
28 cmd++;
29 }
30 }
31
32 for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
33 if (!strcmp(cmds[i].name,arg[0])) {
34 if (n != cmds[i].numargs) {
35 ALOGE("%s requires %d arguments (%d given)\n",
36 cmds[i].name, cmds[i].numargs, n);
37 } else {
38 ret = cmds[i].func(arg + 1, reply);
39 }
40 goto done;
41 }
42 }
43 ALOGE("unsupported command '%s'\n", arg[0]);
44
45 done:
46 if (reply[0]) {
47 n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
48 } else {
49 n = snprintf(cmd, BUFFER_MAX, "%d", ret);
50 }
51 if (n > BUFFER_MAX) n = BUFFER_MAX;
52 count = n;
53
54 // ALOGI("reply: '%s'\n", cmd);
55 if (writex(s, &count, sizeof(count))) return -1;
56 if (writex(s, cmd, count)) return -1;
57 return 0;
58 }
installd服务可执行的命令:
1 struct cmdinfo cmds[] = {
 2     { "ping",                 0, do_ping },
 3     { "install",              5, do_install },
 4     { "dexopt",               9, do_dexopt },
 5     { "markbootcomplete",     1, do_mark_boot_complete },
 6     { "movedex",              3, do_move_dex },
 7     { "rmdex",                2, do_rm_dex },
 8     { "remove",               3, do_remove },
 9     { "rename",               2, do_rename },
10     { "fixuid",               4, do_fixuid },
11     { "freecache",            2, do_free_cache },
12     { "rmcache",              3, do_rm_cache },
13     { "rmcodecache",          3, do_rm_code_cache },
14     { "getsize",              8, do_get_size },
15     { "rmuserdata",           3, do_rm_user_data },
16     { "cpcompleteapp",        6, do_cp_complete_app },
17     { "movefiles",            0, do_movefiles },
18     { "linklib",              4, do_linklib },
19     { "mkuserdata",           5, do_mk_user_data },
20     { "mkuserconfig",         1, do_mk_user_config },
21     { "rmuser",               2, do_rm_user },
22     { "idmap",                3, do_idmap },
23     { "restorecondata",       4, do_restorecon_data },
24     { "createoatdir",         2, do_create_oat_dir },
25     { "rmpackagedir",         1, do_rm_package_dir },
26     { "linkfile",             3, do_link_file }
27 };
应用程序安装
1 static int do_install(char **arg, char reply[REPLY_MAX] __unused)
2 {
3 return install(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4]); /* uuid, pkgname, uid, gid, seinfo */
4 }
do_install 函数直接调用frameworks\base\cmds\installd\commands.c中的install函数来安装
1 int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
2 {
3 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
4 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
5 return -1;
6 }
7
8 std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
9 const char* pkgdir = _pkgdir.c_str();
10
11 if (mkdir(pkgdir, 0751) < 0) {
12 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
13 return -1;
14 }
15 if (chmod(pkgdir, 0751) < 0) {
16 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
17 unlink(pkgdir);
18 return -1;
19 }
20
21 if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) {
22 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
23 unlink(pkgdir);
24 return -errno;
25 }
26
27 if (chown(pkgdir, uid, gid) < 0) {
28 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
29 unlink(pkgdir);
30 return -1;
31 }
32
33 return 0;
34 }
三.
PackageInstaller 安装apk
PackageInstaller
本身就是一个apk,代码位置在
“/packages/apps/PackageInstaller/”,用于显示安装应用的界面的一个apk。安装过程其实是通过PackageManagerService
调用Installer来完成的。
安装过程中涉及到的类文件:
PackageInstallerActivity.java:
在文件管理器里点击apk后就会调用该类,主要用于显示要安装的apk的一些权限信息。
InstallAppProgress.java:
当看完所有权限后,点安装后就会调用该类,用于显示安装进度,这时候PackageManagerService就在默默的安装应用。
ApplicationPackageManager.java:
这是类是PackageManager的子类,我们使用mContext.getPackageManager得到的其实就是ApplicationPackageManager的对象,它爹PackageManager是个抽象类,对外的方法都定义在里面。
PackageParser.java:
解析app,主要解析apk中的AndroidManifest.xml,解析里面的四大组件以及权限信息放入内存里,最后写到packages.xml和package.list(/data/system下)中。
AssetManager.java:
把AndroidManifest.xml从app中拿出来给PackageParser.java去解析。
DefaultContainerService.java:
这个服务用于检查存储状态,得到合适的安装位置。
Installer.java:
PackageManagerService调用它去执行安装,他会把PackageManagerService传过来的数据封装成命令,然后让底层的Installer去执行。
PackageManagerService.java:
管理app的安装、移动、卸载、查询等。
实现原理:
1.
点击文件管理器中的apk时,文件管理器会启动PackageInstaller的PackageInstallerActivity界面,并且将apk的信息通过intent传递给PackageInstallerActivity。
2.
PackageInstaller启动过后会检查是否开启未知来源,未开启就需要先进入设置设置后,方可继续安装;
1 @Override
2 protected void onCreate(Bundle icicle) {
3 ......
4 mPm = getPackageManager();
5 boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
6 ......
7 initiateInstall();
8 }
之后会依次调用initiateInstall()->startInstallConfirm();
initiateInstall方法负责检查是否已经安装过,是否是系统应用等;
startInstallConfirm负责初始化界面,显示权限信息;
当点击安装按钮时,启动安装,切换界面到InstallAppProgress。
 1 private void startInstall() {
 2         // Start subactivity to actually install the application
 3         Intent newIntent = new Intent();
 4         newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
 5                 mPkgInfo.applicationInfo);
 6         newIntent.setData(mPackageURI);
 7         newIntent.setClass(this, InstallAppProgress.class);
 8         ........
 9         startActivity(newIntent);
10         finish();
11     }
3.
在InstallAppProgress中会调用initView去初始化界面并调用ApplicationPackageManager的installPackageWithVerificationAndEncryption方法来安装.
1 @Override
2 public void onCreate(Bundle icicle) {
3 ......
4 initView();
5 }
 1 public void initView() {
 2         ......
 3         if ("package".equals(mPackageURI.getScheme())) {
 4             try {
 5                 pm.installExistingPackage(mAppInfo.packageName);
 6                 observer.packageInstalled(mAppInfo.packageName,
 7                         PackageManager.INSTALL_SUCCEEDED);
 8             } catch (PackageManager.NameNotFoundException e) {
 9                 observer.packageInstalled(mAppInfo.packageName,
10                         PackageManager.INSTALL_FAILED_INVALID_APK);
11             }
12         } else {
13             pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
14                     installerPackageName, verificationParams, null);
15         }
16     }
4.
ApplicationPackageManager的installPackageWithVerificationAndEncryption里也是调用PMS的installPackage
方法.
1 @Override
2 public void installPackageWithVerificationAndEncryption(Uri packageURI,
3 IPackageInstallObserver observer, int flags, String installerPackageName,
4 VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
5 installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
6 installerPackageName, verificationParams, encryptionParams);
7 }
1 private void installCommon(Uri packageURI,
2 PackageInstallObserver observer, int flags, String installerPackageName,
3 VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
4 if (!"file".equals(packageURI.getScheme())) {
5 throw new UnsupportedOperationException("Only file:// URIs are supported");
6 }
7 if (encryptionParams != null) {
8 throw new UnsupportedOperationException("ContainerEncryptionParams not supported");
9 }
10
11 final String originPath = packageURI.getPath();
12 try {
13 mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
14 verificationParams, null);
15 } catch (RemoteException ignored) {
16 }
17 }
5.
.installPackage()
方法里,首先会获取设置中的用户安装位置,并且会把InstallParams对象和安装位置flag封装到Message里,然后发出一个消息。
1 @Override
2 public void installPackage(String originPath, IPackageInstallObserver2 observer,
3 int installFlags, String installerPackageName, VerificationParams verificationParams,
4 String packageAbiOverride) {
5 installPackageAsUser(originPath, observer, installFlags, installerPackageName,
6 verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
7 }
1 @Override
2 public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
3 int installFlags, String installerPackageName, VerificationParams verificationParams,
4 String packageAbiOverride, int userId) {
5
6 ......
7
8 final Message msg = mHandler.obtainMessage(INIT_COPY);
9 msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
10 null, verificationParams, user, packageAbiOverride, null);
11 mHandler.sendMessage(msg);
12 }
6.
PackageManagerService.PackageHandler#doHandleMessage
处理INIT_COPY、MCS_BOUN消息。
如果msg.what
是INIT_COPY:
则连接DefaultContainerService服务,把我们要安装的信息放到HandlerParams的一个List中mPendingInstalls,然后发送MCS_BOUND消息。
如果msg.what
是MCS_BOUN:
则通过
“HandlerParams
params = mPendingInstalls.get(0)”
读取出我们要安装的包信息,然后清除该包信息,如果还有其他包就继续发MCS_BOUND这个消息,循环,直到都安装完了。
然后执行PackageManagerService.HandlerParams#startCopy。
7.
 执行HandlerParams#startCopy
1 final boolean startCopy() {
 2             boolean res;
 3             try {
 4                 if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
 5
 6                 if (++mRetries > MAX_RETRIES) {
 7                     Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
 8                     mHandler.sendEmptyMessage(MCS_GIVE_UP);
 9                     handleServiceError();
10                     return false;
11                 } else {
12                     handleStartCopy();
13                     Slog.i(TAG, "Apk copy done");
14                     res = true;
15                 }
16             } catch (RemoteException e) {
17                 if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");
18                 mHandler.sendEmptyMessage(MCS_RECONNECT);
19                 res = false;
20             }
21             handleReturnCode();
22             return res;
23         }
startCopy有两个重要的方法:handleStartCopy 和 handleReturnCode
调用handleStartCopy:
handleStartCopy方法中会检查应用是否能安装;
如不合法则返回FAILED的CODE,接着会调用DefaultContainerService的getMinimalPackageInfo方法,该方法用于获取存储状态,返回合适的安装位置;经过一系列的判断,如果返回码是INSTALL_SUCCEEDED,那接下来就会调用InstallParams的copyApk;如果安装到内置,调用的就是FileInstallArgs的copyApk方法;如安装到外置就调用AsecInstallArgs的copyApk方法;AsecInstallArgs和FileInstallArgs都是InstallParams的子类。
copyApk方法中会依次调用FileInstallArgs
的createCopyFile->PackageManagerService的createTempPackageFile方法去创建临时文件。
handleStartCopy有两个作用:
1.
final InstallArgs args = createInstallArgs(this);
2.
返回ret标识是否安装成功的。
调用handleReturnCode:
1 @Override
2 void handleReturnCode() {
3 if (mArgs != null) {
4 processPendingInstall(mArgs, mRet);
5 }
6 }
也就是调用installPackageLI(args, true, res)。
1        if (replace) {
2             replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
3                     installerPackageName, volumeUuid, res);
4         } else {
5             installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
6                     args.user, installerPackageName, volumeUuid, res);
7         }
如果是第一次安装,则执行installNewPackageLI方法。
之后的代码和PackageManagerService安装系统软件一样了。
PackageManagerService#installNewPackageLI
-->PackageManagerService#scanPackageLI(android.content.pm.PackageParser.Package, int, int, long, android.os.UserHandle)
-->PackageManagerService#scanPackageDirtyLI
-->PackageManagerService#createDataDirsLI
 1 private int createDataDirsLI(String volumeUuid, String packageName, int uid, String seinfo) {
 2         int[] users = sUserManager.getUserIds();
 3         int res = mInstaller.install(volumeUuid, packageName, uid, uid, seinfo);
 4         if (res < 0) {
 5             return res;
 6         }
 7         for (int user : users) {
 8             if (user != 0) {
 9                 res = mInstaller.createUserData(volumeUuid, packageName,
10                         UserHandle.getUid(user, uid), user, seinfo);
11                 if (res < 0) {
12                     return res;
13                 }
14             }
15         }
16         return res;
17     }
调用Installer的createUserData和install方法,连接底层的Installed服务来安装。
备注: 关于adb工具安装apk的文章, 可以参考 http://blog.csdn.net/gaugamela/article/details/52691084
APK安装流程概述的更多相关文章
- Android源代码解析之(十三)-->apk安装流程
		转载请标明出处:一片枫叶的专栏 上一篇文章中给大家分析了一下android系统启动之后调用PackageManagerService服务并解析系统特定文件夹.解析apk文件并安装的过程,这个安装过程实 ... 
- 安卓逆向基础(001)-APK安装流程
		1.在/data/app下以报名为文件夹名新建文件夹 APK包存放在这里 以及lib文件 存放so 2./data/dalvik-cache 存放dex dex是dalvik虚拟机可执行文件 3./d ... 
- Android Activity启动流程, app启动流程,APK打包流程, APK安装过程
		1.Activity启动流程 (7.0版本之前) 从startActivity()开始,最终都会调用startActivityForResult() 在该方法里面会调用Instrumentation. ... 
- 【转】android Apk打包过程概述_android是如何打包apk的
		最近看了老罗分析android资源管理和apk打包流程的博客,参考其他一些资料,做了一下整理,脱离繁琐的打包细节和数据结构,从整体上概述了apk打包的整个流程. 流程概述: 1.打包资源文件,生成 ... 
- android Apk打包过程概述_android是如何打包apk的
		流程概述:1.打包资源文件,生成R.java文件2.处理aidl文件,生成相应java 文件3.编译工程源代码,生成相应class 文件4.转换所有class文件,生成classes.dex文件5.打 ... 
- 深度探究apk安装过程
		一.先验知识 0.PcakageaManagerService版本号变化 1.概述 2.PackageManagerService服务启动流程 3. PackageManagerService入口 二 ... 
- Android中APK安装过程及原理解析
		[原文] 来自华为内部资料 应用安装是智能机的主要特点,即用户可以把各种应用(如游戏等)安装到手机上,并可以对其进行卸载等管理操作.APK是Android Package的缩写,即android安装包 ... 
- Android开发——Android系统启动以及APK安装、启动过程
		0. 前言 从Android手机打开开关,到我们可以使用其中的app时,这个启动过程到底是怎么样的? 1. 系统上电 当给Android系统上电,在电源接通的瞬间,CPU内的寄存器和各引脚均会被 ... 
- iOS 最新版 CocoaPods 的安装流程
		iOS 最新版 CocoaPods 的安装流程1.移除现有Ruby默认源$gem sources --remove https://rubygems.org/2.使用新的源$gem sources - ... 
随机推荐
- java IO流体系--通识篇
			1.I/O流是什么 Java的I/O流是实现编程语言的输入/输出的基础能力,操作的对象有外部设备.存储设备.网络连接等等,是所有服务器端的编程语言都应该具备的基础能力. I = Input(输入),输 ... 
- php7废弃mcrypt加密,使用openssl替换
			概要: php从7.0升级到7.1废弃了一个扩展,即mcrypt扩展,虽然安装上扩展也能正常使用,但是会发出警告,告诉我们mcrypt相关方法已经被废弃,到了7.2,已经被移除,因此不建议继续使用. ... 
- php jsonp接口
			//jsonp回调 $callback = isset($_GET['callback']) ? trim($_GET['callback']) : ''; //jsonp回调参数,必需 $cgc_k ... 
- php 23种设计模式 - 设计模式简介以及分类
			一. Introduction[介绍] 设计模式:提供了一种广泛的可重用的方式来解决我们日常编程中常常遇见的问题.设计模式并不一定就是一个类库或者第三方框架,它们更多的表现为一种思想并且广泛地应用在系 ... 
- Redis 大 key 问题总结
			多大的 key 算大? 阿里云Redis 最佳实践中提到 合理的 Key 中 Value 的字节大小,推荐小于10 KB.过大的 Value 会引发数据倾斜.热点Key.实例流量或 CPU 性能被占满 ... 
- Redis 中的 set 和 sorted set 如何使用,源码实现分析
			set 和 sorted set 前言 set 常见命令 set 的使用场景 看下源码实现 insert dict sorted set 常见的命令 使用场景 分析下源码实现 ZADD ZRANGE ... 
- Java基础——Object类
			一.概述: Object是类层次结构的根,每个类都可以将Object作为超类.所有类都直接或者间接的继承该类 有一个构造方法 public Object() 面向对象中子类的构造方法默认访问的是父类的 ... 
- Linux 查看文件大小并按照大小排序
			使用df 命令查看当前系统磁盘的使用情况: [root@node ~]# df -Th Filesystem Type Size Used Avail Use% Mounted on /dev/map ... 
- Linux的总线设备驱动模型
			裸机编写驱动比较自由,按照手册实现其功能即可,每个人写出来都有很大不同: 而Linux中还需要按照Linux的驱动模型来编写,也就是需要按照"模板"来写,写出来的驱动就比较统一. ... 
- 除了增删改查你对MySQL还了解多少?
			目录 除了增删改查你对MySQL还了解多少? MySQL授权远程连接 创建用户.授权 客户端与服务器连接的过程 TCP/IP 命名管道和共享内存 Unix域套接字文件 查询优化 MySQL中走与不走索 ... 
