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安装流程概述的更多相关文章

  1. Android源代码解析之(十三)--&gt;apk安装流程

    转载请标明出处:一片枫叶的专栏 上一篇文章中给大家分析了一下android系统启动之后调用PackageManagerService服务并解析系统特定文件夹.解析apk文件并安装的过程,这个安装过程实 ...

  2. 安卓逆向基础(001)-APK安装流程

    1.在/data/app下以报名为文件夹名新建文件夹 APK包存放在这里 以及lib文件 存放so 2./data/dalvik-cache 存放dex dex是dalvik虚拟机可执行文件 3./d ...

  3. Android Activity启动流程, app启动流程,APK打包流程, APK安装过程

    1.Activity启动流程 (7.0版本之前) 从startActivity()开始,最终都会调用startActivityForResult() 在该方法里面会调用Instrumentation. ...

  4. 【转】android Apk打包过程概述_android是如何打包apk的

    最近看了老罗分析android资源管理和apk打包流程的博客,参考其他一些资料,做了一下整理,脱离繁琐的打包细节和数据结构,从整体上概述了apk打包的整个流程.   流程概述: 1.打包资源文件,生成 ...

  5. android Apk打包过程概述_android是如何打包apk的

    流程概述:1.打包资源文件,生成R.java文件2.处理aidl文件,生成相应java 文件3.编译工程源代码,生成相应class 文件4.转换所有class文件,生成classes.dex文件5.打 ...

  6. 深度探究apk安装过程

    一.先验知识 0.PcakageaManagerService版本号变化 1.概述 2.PackageManagerService服务启动流程 3. PackageManagerService入口 二 ...

  7. Android中APK安装过程及原理解析

    [原文] 来自华为内部资料 应用安装是智能机的主要特点,即用户可以把各种应用(如游戏等)安装到手机上,并可以对其进行卸载等管理操作.APK是Android Package的缩写,即android安装包 ...

  8. Android开发——Android系统启动以及APK安装、启动过程

    0. 前言   从Android手机打开开关,到我们可以使用其中的app时,这个启动过程到底是怎么样的? 1.  系统上电 当给Android系统上电,在电源接通的瞬间,CPU内的寄存器和各引脚均会被 ...

  9. iOS 最新版 CocoaPods 的安装流程

    iOS 最新版 CocoaPods 的安装流程1.移除现有Ruby默认源$gem sources --remove https://rubygems.org/2.使用新的源$gem sources - ...

随机推荐

  1. JAVA——类与对象

    目录 类与对象 一.类 二.对象 2.1对象的内存布局形式 三.类与对象 3.1如何创建 3.2如何访问属性 3.2类与对象的分配机制 3.2.1Java内存的结构分析 注意事项和细节 类与对象 为什 ...

  2. STP详解-STP、RSTP、MSTP

    STP详解 01 冗余链路中存在的问题 如图所示LSW1和LSW2之间有两条线路相连,它们之间任何一条链路出现故障另外一条线路可以马上顶替出现故障的那条链路,这样可以很好的解决单链路故障引起的网络中断 ...

  3. 移动端开发为什么使用@2x@3x图片

    物理.逻辑与位图像素的概念 关于设备物理像素和逻辑像素,这两个像素一个是实体的,一个是抽象的单位.除此之外还有一个不可忽视的像素,就是位图像素. 物理像素(设备像素):指的是设备屏幕实际拥有的像素点. ...

  4. 结合AngularJS实现拖拽

    最近项目中要实现,左侧树向右侧树中元素的拖拽功能,开始在网上看了好多ng-drag等等操作,都没有实现预想的效果,偶然发现一篇博客,然后根据博客改编,实现了自己想要的效果.下面简单的分析一下实现过程. ...

  5. CF708C题解

    挺简单的一道数据结构... 首先考虑这个"改造"的本质,很明显是把一颗子树塞到了另一个节点下面. 考虑一个节点可能成为重心的条件.条件很明显是只有一颗子树的大小大于 \(\frac ...

  6. CF498B题解

    咋黑色啊,这不是看到数据范围就去想 \(O(nT)\) 的做法吗? 然后仔细想想最靠谱的就是 DP. 设 \(dp[n][T]\) 表示听完第 \(n\) 首歌,总共听了 \(T\) 秒. 很明显有 ...

  7. 基于python 实现冒泡排序算法

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/11/17 14:42 # @Author : gylhaut # @Site ...

  8. [SPDK/NVMe存储技术分析]008 - RDMA概述

    毫无疑问地,用来取代iSCSI/iSER(iSCSI Extensions for RDMA)技术的NVMe over Fabrics着实让RDMA又火了一把.在介绍NVMe over Fabrics ...

  9. 74CMS 3.0 存储型XSS漏洞

    一. 启动环境 1.双击运行桌面phpstudy.exe软件 2.点击启动按钮,启动服务器环境 二.代码审计 1.双击启动桌面Seay源代码审计系统软件 2.因为74CMS3.0源代码编辑使用GBK编 ...

  10. POI完成Excel文件的读和写

    简介 Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office(Excel.WORD.PowerPo ...