原文地址:http://blog.csdn.net/jinzhuojun/article/details/25542011
其实对于apk包的安装,4.4和之前版本没大的差别。Android中app安装主要有以下几种情况:系统启动时安装,adb命令安装,Google Play上下载安装和通过PackageInstaller安装。安装的最核心方法是scanPackageLI(),以上几个安装方式最后都是调用这个函数完成主要工作的,区别在于在此之前的处理过程不同。本文以前两种为主,简要介绍这四种安装过程。
一个最一般的apk包(不是系统app,没有共享lib,不是装在sd上或是forward-lock的app)装完后内容会体现在这么几个目录:
/data/app // apk包
/data/app-lib// native lib
/data/data //数据目录,其中的lib目录指向上面的/data/app-lib目录
/data/dalvik-cache/data@app@
一、启动时安装
Android启动时会把已有的app安装一遍,过程主要分三部分:读取安装信息,扫描安装,写回安装信息。读取和写回主要是针对于一坨安装信息文件。这些信息保证了启动后app与上一次的一致。关键步是扫描指定目录下的apk并安装。Android中apk主要分布在以下几个目录,意味着启动时要扫描的主要也是这几个目录:
系统核心应用:/system/priv-app
系统app:/system/app
非系统app:/data/app(安装于手机存储的一般app)或/mnt/asec/
受DRM保护app:/data/app-private
vendor-specific的app: /vendor/app
资源型app:/system/framework
整个启动时安装的流程大体如下:
几个同名函数一开始看得会有些混淆,内层scanPackageLI()比较复杂这里省略细节。下面更加详细地分析下流程。故事从System Server开始,实现在/frameworks/base/services/java/com/android/server/SystemServer.java中:
241 pm = PackageManagerService.main(context, installer, 242 factoryTest != SystemServer.FACTORY_TEST_OFF, 243 onlyCore);
调用
PMS
的
main()
函数,其实现位于
/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java
:
1040 public static final IPackageManager main(Context context, Installer installer, 1041 boolean factoryTest, boolean onlyCore) { 1042 PackageManagerService m = new PackageManagerService(context, installer, 1043 factoryTest, onlyCore); 1044 ServiceManager.addService('package', m); 1045 return m; 1046 }
这里构造了PMS并加到ServiceManager中,这样其它的组件就可以用该服务了。PMS的构造函数中:
1084 mSettings = new Settings(context); // 用于存放和操作动态安装信息,具体地说,如uid, permission等。 ... 1115 mInstaller = installer; // installd daemon的proxy类。 … 1124 mHandlerThread.start(); // 启动PMS的工作线程。 1125 mHandler = new PackageHandler(mHandlerThread.getLooper()); // PMS会通过mHandler丢活给工作线程。 ... 1129 File dataDir = Environment.getDataDirectory(); // /data 1130 mAppDataDir = new File(dataDir, 'data'); // /data/data 1131 mAppInstallDir = new File(dataDir, 'app'); // /data/app 1132 mAppLibInstallDir = new File(dataDir, 'app-lib'); // /data/app-lib
可以看到PMS除了主线程,还会有一个叫PackageManager的工作线程。它主要是用在其它安装方式中,因为启动时没什么用户交互,基本上不需要把工作交给后台。
262 final HandlerThread mHandlerThread = new HandlerThread('PackageManager', 263 Process.THREAD_PRIORITY_BACKGROUND);
权限信息在
/etc/permissions
目录中,由
readPermissions()
函数读取,保存在
Settings
中的
mPermissions
中。接下来在
PMS
构造函数中调用
readLPw()
来解析
packages.xml
文件得到上次的安装信息。
1144 mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false), 1145 mSdkVersion, mOnlyCore);
Android启动时要扫描和安装现有app。或许是为了防止corrupted信息的存在,或许是为了能在升级系统或更新系统属性后保持app也valid,亦或是因为有些信息(如uid)必须是动态生成和调整的。总之,为了要还原现有app的安装信息,这些信息被放在/data/system/packages.xml里,由Settings管理。另外/data/system/packages.list记录了app的uid和数据路径等信息。readLPw()就是用于恢复这些信息,实现位于/frameworks/base/services/java/com/android/server/pm/Settings.java。readLPw()先打开packages.xml,再通过XmlPullParser类来解析其内容。它会根据不同的tag调用相应的函数来读取信息:
1712 String tagName = parser.getName(); 1713 if (tagName.equals('package')) { 1714 readPackageLPw(parser); 1715 } else if (tagName.equals('permissions')) { 1716 readPermissionsLPw(mPermissions, parser); 1717 } else if (tagName.equals('permission-trees')) { 1718 readPermissionsLPw(mPermissionTrees, parser); 1719 } else if (tagName.equals('shared-user')) { 1720 readSharedUserLPw(parser); 1721 } else if (tagName.equals('preferred-packages')) { 1722 // no longer used. 1723 } else if (tagName.equals('preferred-activities')) { 1724 // Upgrading from old single-user implementation; 1725 // these are the preferred activities for user 0. 1726 readPreferredActivitiesLPw(parser, 0); 1727 } else if (tagName.equals('updated-package')) { 1728 readDisabledSysPackageLPw(parser);
packages.xml中的一个apk包对应的package结构大体如下:
...
325 p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, 326 vc, pkgFlags); 327 p.appId = uid; 328 if (addUserIdLPw(uid, p, name)) { 329 mPackages.put(name, p); 330 return p; 331 }
其中readPackageLPw()调用addPackageLPw()注册app信息到变量mPackages中,uid信息到mUserIds/mOtherUserIds中,准确地说,应该是把这些信息从文件恢复回去。addPackageLPw()会创建PackageSetting,该类描述了该apk包的安装信息。
注意Android中app的uid的范围区间是FIRST_APPLICATION_UID ~LAST_APPLICATION_UID,即10000 ~ 99999,FIRST_APPLICATION_UID之下的给系统应用。
碰到shared user就更麻烦了,因为有时多个app为了共享权限会共享一个uid。如果一个app要用共享uid,需要在apk的AndroidManifest.xml文件中申明android:sharedUserId='...',详见 http://developer.android.com/guide/topics/manifest/manifest-element.html。 这时就要先为其创建PendingPackage并放到mPendingPackages等共享uid部分搞定了再处理。在packages.xml中共享用户表示为:
...
readSharedUserLPw()用来处理app安装信息中的共享用户部分。它会调用addSharedUserLPw()来添加共享用户。addSharedUserLPw()为共享用户创建SharedUserSetting类(SharedUserSetting包含了一个PackageSetting的集合),再调用addUserIdLPw()函数注册到mUserIds中(或mOtherUserIds),成功的话另外还会写入mSharedUsers中。
345 s = new SharedUserSetting(name, pkgFlags); 346 s.userId = uid; 347 if (addUserIdLPw(uid, s, name)) { 348 mSharedUsers.put(name, s); 349 return s; 350 }
综合上面的信息,就有了下面这样的结构:
我们知道packages.xml放了app在之前安装时的配置信息。这里可以有两点推论:当一个app卸载后packages.xml中该app的信息也被删除了。当卸载以后下一次安装同一个app时会重新生成,uid不会被保留。
1199 if (dalvik.system.DexFile.isDexOptNeeded(lib)) { 1200 alreadyDexOpted.add(lib); 1201 mInstaller.dexopt(lib, Process.SYSTEM_UID, true); 1202 didDexOpt = true; 1203 }
1231 for (int i=0; i 1276 // Find base frameworks (resource packages without code). 1277 mFrameworkInstallObserver = new AppDirObserver( 1278 frameworkDir.getPath(), OBSERVER_EVENTS, true, false); 6384 public void onEvent(int event, String path) { ... 6450 p = scanPackageLI(fullPath, flags, 6451 SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME, 6452 System.currentTimeMillis(), UserHandle.ALL); ... 6460 synchronized (mPackages) { 6461 updatePermissionsLPw(p.packageName, p, 6462 p.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL : 0); 6463 } ... 6471 synchronized (mPackages) { 6472 mSettings.writeLPr(); 6473 } 1280 scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM 1281 | PackageParser.PARSE_IS_SYSTEM_DIR 1282 | PackageParser.PARSE_IS_PRIVILEGED, 1283 scanMode | SCAN_NO_DEX, 0); 1380 mAppInstallObserver = new AppDirObserver( 1381 mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false); 1382 mAppInstallObserver.startWatching(); 1383 scanDirLI(mAppInstallDir, 0, scanMode, 0); … 1446 updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL 1447 | (regrantPermissions 1448 ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL) 1449 : 0)); ... 1457 // can downgrade to reader 1458 mSettings.writeLPr(); scanDirLI() scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); PackageParser pp = new PackageParser(scanPath); final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags); assmgr = new AssetManager(); parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); pkg = parsePackage(res, parser, flags, errorText); // parse AndroidManifest.xml ... PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user); 1034 String tagName = parser.getName(); 1035 if (tagName.equals('application')) { 1036 if (foundApp) { 1037 if (RIGID_PARSER) { 1038 outError[0] = ' 回到readLPw()后,处理前面那些因为用了共享用户而待处理的app,也就是mPendingPackages里的那坨。完了再回到PackageManagerService()。mSharedLibraries里放的一些共享的java库,这里会调用dexopt()对它们进行优化。alreadyDexOpted记录已经运行过dexopt的文件,像启动类和上面的共享库。下面是对framework里的包和类进行优化。接下来,监控/system/framework目录并扫描该目录。这里用Observer模式来监视目录变动。它依赖于Linux kernel提供的Inotify机制。实现主要位于/frameworks/base/core/java/android/os/FileObserver.java和/frameworks/base/core/jni/android_util_FileObserver.cpp。对于它的继承类(如AppDirObserver),只要实现onEvent()方法来处理文件或目录变动即可。onEvent()的实现比如/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java中:扫描该目录的目的是要安装里边的apk包。主要实现函数是scanDirLI():对于其它几个目录(/system/priv-app,/system/app,/vendor/app, /data/app, /data/app-private),也是一样的:全安装好了就可以更新权限信息并且写回安装信息了。这样启动时安装主要工作就差不多完成了。下面回头看一下重头戏 - 目录的扫描和安装,也就是scanDirLI()函数:可以看到scanPackageLI()和parsePackage()皆有重载版本。基本上内层的版本才是做事的。内层的parsePackage(res, ...)函数用于解析AndroidManifest.xml文件。实现在/frameworks/base/core/java/android/content/pm/PackageParser.java。至于AndroidManifest.xml是apk中必不可少的配置文件。详见http://developer.android.com/guide/topics/manifest/manifest-intro.html,没有的话Android压根不让你装。比较重要的如parseApplication()是解析application标签里的东西。application标签里包含Android四大组件(Activity, Receiver, Service, Content Provider)信息和库等信息。一顿解析后,返回结果PackageParser.Package对象pkg,这个类基本上就包含了AndroidManifest.xml里的信息。接下来scanPackageLI(pkg, ...)被调用,前面返回的解析结果pkg被当作参数传入。scanPackageLI(pkg, ...)干的事还挺多的。如处理共享用户,注册包信息,调用NativeLibraryHelper和Installer的相关函数进行安装等等。如果该app使用了共享用户,则调用getSharedUserLPw()函数获取该共享uid的SharedUserSetting,没有的话就新建,然后分配uid: 245 SharedUserSetting getSharedUserLPw(String name, 246 int pkgFlags, boolean create) { 247 SharedUserSetting s = mSharedUsers.get(name); 248 if (s == null) { 249 if (!create) { 250 return null; 251 } 252 s = new SharedUserSetting(name, pkgFlags); 253 s.userId = newUserIdLPw(s); 254 Log.i(PackageManagerService.TAG, 'New shared user ' + name + ': id=' + s.userId); 255 // < 0 means we couldn't assign a userid; fall out and return 256 // s, which is currently null 257 if (s.userId >= 0) { 258 mSharedUsers.put(name, s); 259 } 260 } 261 262 return s; 263 } 在scanPackageLI(pkg, ...)函数中,下面调用getPackageLPw()得到该apk包的PackageSetting对象,有些在前面readPackageLPw()时就已经恢复好了,还没有的那些这儿就会新建: 4302 // Just create the setting, don't add it yet. For already existing packages 4303 // the PkgSetting exists already and doesn't have to be created. 4304 pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile, 4305 destResourceFile, pkg.applicationInfo.nativeLibraryDir, 4306 pkg.applicationInfo.flags, user, false); getPackageLPw()实现在/frameworks/base/services/java/com/android/server/pm/Settings.java中: 392 private PackageSetting getPackageLPw(String name, PackageSetting origPackage, 393 String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, 394 String nativeLibraryPathString, int vc, int pkgFlags, 395 UserHandle installUser, boolean add, boolean allowInstall) { … 457 p = new PackageSetting(name, realName, codePath, resourcePath, 458 nativeLibraryPathString, vc, pkgFlags); ... 520 // Assign new user id 521 p.appId = newUserIdLPw(p); newUserIdLPw()函数为app分配uid。这样,该应用对应的uid就设置好了。 回到scanPackageLI()中,下面设置进程名,进程名默认就是包名。所以我们在ps里看到的都是包名。 4422 pkg.applicationInfo.processName = fixProcessName( 4423 pkg.applicationInfo.packageName, 4424 pkg.applicationInfo.processName, 4425 pkg.applicationInfo.uid); 对于大部分全新安装的一般应用而言,接下来为应用创建数据目录: 3987 private int createDataDirsLI(String packageName, int uid, String seinfo) { 3988 int[] users = sUserManager.getUserIds(); 3989 int res = mInstaller.install(packageName, uid, uid, seinfo); ... 3993 for (int user : users) { 3994 if (user != 0) { 3995 res = mInstaller.createUserData(packageName, 3996 UserHandle.getUid(user, uid), user); Installer是一个代理类,它会和后台的installd通信并让installd完成具体工作。installd的实现位于/frameworks/native/cmds/installd/commands.c,install()会创建app目录(/data/data/ ),并作lib目录的软链接,如/data/data/xxx/lib -> /data/app-lib/xxx。 下面设置原生库目录为/data/data/ 4556 if (pkgSetting.nativeLibraryPathString == null) { 4557 setInternalAppNativeLibraryPath(pkg, pkgSetting); 4558 } else { 4559 pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathString; 4560 } ... 4577 if (pkg.applicationInfo.nativeLibraryDir != null) { 4578 try { 4579 File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir); ... 4605 try { 4606 if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) { 4607 Slog.e(TAG, 'Unable to copy native libraries'); 4608 mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR; 4609 return null; 4638 if ((scanMode&SCAN_NO_DEX) == 0) { 4639 if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false) 4640 == DEX_OPT_FAILED) { 4641 mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT; 4642 return null; 4643 } 4644 } 这里调用copyNativeLibrariesForInternalApp(),它会调用NativeLibraryHelper.copyNativeBinariesIfNeededLI()把apk里的原生库解压出来放到/data/app-lib的对应目录下。接下来PMS调用performDexOptLI()优化Java的bytecode,即dex文件。真正的工作还是在后台installd进程中完成, installd中的dexopt()函数会根据当前是运行dalvik还是art虚拟机来选择调用run_dexopt()或run_dex2oat()。 741 if (strncmp(persist_sys_dalvik_vm_lib, 'libdvm', 6) == 0) { 742 run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags); 743 } else if (strncmp(persist_sys_dalvik_vm_lib, 'libart', 6) == 0) { 744 run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags); 745 } else { 746 exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */ 747 } 前者适用于dalvik,将dex优化成odex文件。后者适用于art,将dex直接一步到位编译成oat文件(也就是可执行代码)了。由于下层是执行了/system/bin/dexopt或/system/bin/dex2oat文件,dexopt()将之放到子进程去做,自己作为父进程等待它结束。以art为例,/system/bin/dex2oat被调用(实现位于/art/dex2oat/dex2oat.cc)。输出的elf文件放在/data/dalvik-cache/data@app@ @classes.dex。注意对于dalvik和art,这个文件名称相同但性质截然不同。dalvik下,该文件为优化后的bytecode。而art下,这个就是可执行文件了。 如果是更新已有的app,还要让ActivityManager调用killApplication()把进程杀掉。app都更新了,老的还留内存里跑,这不合适。 4743 killApplication(pkg.applicationInfo.packageName, 4744 pkg.applicationInfo.uid, 'update pkg'); 4763 mSettings.insertPackageSettingLPw(pkgSetting, pkg); // PackageSetting <= PackageParser.Package addPackageSettingLPw(p, pkg.packageName, p.sharedUser) mPackages.put(name, p); 4764 // Add the new setting to mPackages 4765 mPackages.put(pkg.applicationInfo.packageName, pkg); 之后将安装的app注册到PMS的mPackages中,mPackges是个Hash表,保存了从包名到PackageParser.Package的映射。注意Settings里也有个mPackages,那里保存的是包名到PackageSetting的映射。前者主要是app配置文件中的信息,而后者是安装过程中的信息。可以粗略理解为一个是静态信息,一个是动态信息。下面把app中的组件信息(content provider, service, receiver, activity)记录到系统中。另外根据前面app配置文件中的权限信息进行初始化。 4811 int N = pkg.providers.size(); 4812 StringBuilder r = null; 4813 int i; 4814 for (i=0; i 回到PMS构造函数中。下面就是收尾工作了。主要包括更新共享库信息,更新权限信息,以及写回安装信息。所有包都解析完了,意味着所有共享库信息都已解析,这儿就可以调用updateAllSharedLibrariesLPw()为那些使用动态库的app绑定动态库信息了。下面updatePermissionsLPw()函数用于赋予app相应权限: 5365 private void updatePermissionsLPw(String changingPkg, 5366 PackageParser.Package pkgInfo, int flags) { ... 5430 // Now update the permissions for all packages, in particular 5431 // replace the granted permissions of the system packages. 5432 if ((flags&UPDATE_PERMISSIONS_ALL) != 0) { 5433 for (PackageParser.Package pkg : mPackages.values()) { 5434 if (pkg != pkgInfo) { 5435 grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0); 5436 } 5437 } 5438 } 5445 private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) { ... 5467 final int N = pkg.requestedPermissions.size(); 5468 for (int i=0; i 1261 void writeLPr() { ... 1315 serializer.startTag(null, 'permission-trees'); 1316 for (BasePermission bp : mPermissionTrees.values()) { 1317 writePermissionLPr(serializer, bp); 1318 } 1319 serializer.endTag(null, 'permission-trees'); 1320 1321 serializer.startTag(null, 'permissions'); 1322 for (BasePermission bp : mPermissions.values()) { 1323 writePermissionLPr(serializer, bp); 1324 } 1325 serializer.endTag(null, 'permissions'); 1326 1327 for (final PackageSetting pkg : mPackages.values()) { 1328 writePackageLPr(serializer, pkg); 1329 } 在AndroidManifest.xml中app会申请一些权限,比如读取位置信息,读取联系人,操作摄像头等等。AndroidManifest.xml中的格式如: 这里的permission_name被放到requestedPermissions,代表该app申请该权限。经过grantPermissionsLPw()里判断能否给予相应权限,如果允许则授予权限(即把权限对应的gid加到app的gid列表中,因为权限在Linux中对应物就是group,由gid表示),并把该权限加到grantedPermissions中,代表已授予该权限。最后,writeLPr()将安装信息写回packages.xml文件,这也是一开始readLPw()读的那个文件。这样下次启动时就可以按照这里边的信息重新安装了。总结下几个主要类的用途:PackageManagerService: apk包安装服务Settings: 管理app的安装信息PackageSetting: app的动态安装信息SharedUserSetting: 共享Linux用户PackageParser.Package: app的静态配置信息。Pm: pm命令实现类Installer: installd daemon代理类HandlerThread: PMS工作线程它们之间的大致关系: 通过adb install命令安装时流程略有不同,主要是scanPackageLI()之前的流程不同。host机上的adb从/system/core/adb/adb.c中的main()开始:main()->adb_commandline()->install_app()->pm_command()->send_shellcommand(),其中会把安装包从host传到guest上的临时目录。 接下来guest里的pm命令(/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java)接手,大体流程如下: runInstall() installPackageWithVerificationAndEncryption() doHandleMessage() // INIT_COPY doHandleMessage() // MCS_BOUND startCopy() InstallParams.handleStartCopy() InstallArgs args = createInstallArgs(this) args.copyApk() // FileInstallArgs或AsecInstallArgs,取决于是否是forward-lock或装在sd card上。 createCopyFile() // 拷贝生成类似于/data/app/vmdl-842267127.tmp这样的临时文件,因为这时候包都没解析,不知道包名。 handleReturnCode() processPendingInstall() //异步方式安装,因为安装过程可能较长。 installPackageLI() 这里用到了一开始提到的PMS工作线程,doHandleMessage()就是工作线程用于处理丢给它的消息的。 这里有几个设计模式值得学习的。首先,Pm中得到PMS的代理类,然后调用installPackageWithVerificationAndEncryption()进行安装。 90 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService('package')); ... 957 mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags, 958 installerPackageName, verificationParams, encryptionParams); 由于安装时间一般较长,这里的obs用了Observer模式来监视安装完成事件。 其次,InstallArgs用了Strategy模式,而createInstallArgs()使用了简单工厂模式。在handleStartCopy()中,只要根据安装类型生成相应的InstallArgs对象,然后调用统一接口copyApk()等就行了。 另外,HandlerParams和其继承类采用了Template method模式。其中基类中的startCopy()是模板函数,继承类实现handleStartCopy(),handleServiceError()和handleReturnCode()来完成不同工作。HandlerParams包含了要工作线程做的工作内容,工作线程只要取出HandlerParams对象,调用其startCopy()接口,因此这里也用了Command模式的思想。 将HandlerParams和InstallArgs组合起来看,它们又组成bridge pattern的变体。 这样把本来一棵层数更深的类树给压扁了,从而通过维度分解降低了复杂性,增强了灵活性。 这里的installPackageLI()做了很多前一种安装方式中scanPackageLI(file, ...)的工作,接着它会根据该app是否是全新安装调用replacePackageLI()或installNewPackageLI()。 9061 if (!args.doRename(res.returnCode, pkgName, oldCodePath)) { // 前面拷贝apk时是随机取了临时名字的,这里用doRename()函数为其“正名”。 ... 9068 if (replace) { 9069 replacePackageLI(pkg, parseFlags, scanMode, args.user, 9070 installerPackageName, res); 9071 } else { 9072 installNewPackageLI(pkg, parseFlags, scanMode, args.user, 9073 installerPackageName, res); 9074 } 8601 private void installNewPackageLI(PackageParser.Package pkg, 8602 int parseFlags, int scanMode, UserHandle user, 8603 String installerPackageName, PackageInstalledInfo res) { ... 8630 PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, 8631 System.currentTimeMillis(), user); 如果是全新的apk,调用installNewPackageLI()进行安装。它调用scanPackageLI()完成主要安装工作。从这开始就熟悉了吧,和启动时安装的流程差不多了,最后调用updateSettingsLI()来更新安装信息。 三、Google Play网络下载安装 Google Play的包名为com.android.vending。由于是闭源的,看不了源码。不过从反汇编粗略地看,应该是先把apk包下载到: /data/data/com.android.providers.downloads/cache/downloadfile.apk 然后调用installPackage()安装,类似于: PackageManager pm = context.getPackageManager(); pm.installPackage(packageURI, observer, flags, null); 接着就和上面一样了:installPackage()->installPackageWithVerification()->installPackageWithVerificationAndEncryption()。 四、点选apk文件安装 这种情况下,会通过PackageInstaller安装app。在/packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallAppProgress.java中: 284 pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, 285 installerPackageName, verificationParams, null); 后面的故事又都熟悉了吧。