enc 临时文件 ren func 切换 网络 manager -c
一. APK 安装简介
APK 为 Android
Package 的缩写。
Android 应用安装有如下四种方式:
1. 系统应用安装――开机时完成,没有安装界面;
2. 网络下载应用安装――通过 market 应用完成,没有安装界面;
3.ADB 工具安装――没有安装界面;
4. 第三方应用安装――通过 SD 卡里的 APK 文件安装,有安装界面,由 packageinstaller.apk 应用处理安装及卸载过程的界面。
应用安装涉及到如下几个目录:
1.system/app---------------- 系统自带的应用程序,获得 adb root 权限才能删除;
2.data/app------------------- 用户程序安装的目录,安装时把 apk
文件复制到此目录;
3.data/data------------------- 存放应用程序的数据;
4.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()
- 启动。
- 1public static PackageManagerService main(Context context, Installer installer,
- 2booleanfactoryTest,boolean onlyCore) {
- 3 PackageManagerService m = HwServiceFactory.getHuaweiPackageManagerService(context, installer,
- 4 factoryTest, onlyCore);
- 5 ServiceManager.addService("package", m);
- 6return 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,
读取安装包信息,并解析成对应的数据结构,包括以下重要文件:
这几个目录在创建 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
- 2class 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
- }
- 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
- 2protected void onCreate(Bundle icicle) {
- 3 ......
- 4 mPm = getPackageManager();
- 5booleanrequestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
- 6 ......
- 7 initiateInstall();
- 8 }
之后会依次调用 initiateInstall()->startInstallConfirm();
initiateInstall 方法负责检查是否已经安装过,是否是系统应用等;
startInstallConfirm 负责初始化界面,显示权限信息;
当点击安装按钮时,启动安装,切换界面到 InstallAppProgress。
- 1private void startInstall() {
- 2// Start subactivity to actually install the application3 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
- 2public 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
- 2public 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
- 2public void installPackage(String originPath, IPackageInstallObserver2 observer,
- 3int installFlags, String installerPackageName, VerificationParams verificationParams,
- 4 String packageAbiOverride) {
- 5 installPackageAsUser(originPath, observer, installFlags, installerPackageName,
- 6 verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
- 7 }
- 1 @Override
- 2public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
- 3int installFlags, String installerPackageName, VerificationParams verificationParams,
- 4 String packageAbiOverride,int userId) {
- 5
- 6 ......
- 7
- 8finalMessage msg = mHandler.obtainMessage(INIT_COPY);
- 9 msg.obj =newInstallParams(origin,null, observer, installFlags, installerPackageName,
- 10null, 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 服务来安装。
APK 安装流程概述
恢复 enc 临时文件 ren func 切换 网络 manager -c
来源: http://www.bubuko.com/infodetail-2152678.html