android系统的程序安装主要通过四种途径安装,分别是:
1.系统开机时加载的apk,这一部分的包主要是系统包和一些用户自己安装的程序,无安装界面。
2.通过网络下载安装的包,这一部分主要通过调用PackageManager安装,有部分界面
3.通过adb安装,没有安装界面
4.通过安装器安装,这一部分主要通过调用PackageInstaller安装
我们通过代码依次分析以上四部分:
系统启动安装:
可能要给android做一个类似白名单的东西,只要加入白名单的程序运行,所以需要看一下 android启动时加载安装程序,也就是PackageManagerService的实现。PackageManagerService是由SystemServer启动的所以我们从SystemServer看起。SystemServer的代码位于frameworks/base/services/java/com/android/server/SystemServer.java,其实现是一个标准的java程序,入口代码如下:
1 public class SystemServer { 2 private static final String TAG = "SystemServer"; 3 //... 4 5 /** 6 * This method is called from Zygote to initialize the system. This will cause the native 7 * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back 8 * up into init2() to start the Android services. 9 */ 10 native public static void init1(String[] args); 11 12 public static void main(String[] args) { 13 //... 14 15 System.loadLibrary("android_servers"); 16 init1(args); 17 }
其中init1完成初始化的工作,从这个函数的定义可以看出这个函数是一个c/c++的函数,需要用到java的JNI技术,这个函数的定义位于base/services/jni/com_android_server_SystemServer.cpp文件中,这个文件的代码比较少可以全部列出来,代码如下:
1 namespace android { 2 3 extern "C" int system_init(); 4 5 static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) 6 { 7 system_init(); 8 } 9 10 /* 11 * JNI registration. 12 */ 13 static JNINativeMethod gMethods[] = { 14 /* name, signature, funcPtr */ 15 { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 }, 16 }; 17 18 int register_android_server_SystemServer(JNIEnv* env) 19 { 20 return jniRegisterNativeMethods(env, "com/android/server/SystemServer", 21 gMethods, NELEM(gMethods)); 22 } 23 24 }; // namespace android
从这段代码可以看出真正调用的函数是system_init,这个函数的定义位于base/cmds/system_server/library/system_init.cpp部分定义如下:
extern "C" status_t system_init() { ALOGI("Entered system_init()"); sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); ALOGI("ServiceManager: %p\n", sm.get()); sp<GrimReaper> grim = new GrimReaper(); sm->asBinder()->linkToDeath(grim, grim.get(), 0); //... jclass clazz = env->FindClass("com/android/server/SystemServer"); if (clazz == NULL) { return UNKNOWN_ERROR; } jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V"); if (methodId == NULL) { return UNKNOWN_ERROR; } env->CallStaticVoidMethod(clazz, methodId); ALOGI("System server: entering thread pool.\n"); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); ALOGI("System server: exiting thread pool.\n"); return NO_ERROR; }
熟悉android的朋友一眼就知道开头几行函数的意义,这几行的作用主要是完成进程间通信。我们重点看下面的几行
1 jclass clazz = env->FindClass("com/android/server/SystemServer"); 2 if (clazz == NULL) { 3 return UNKNOWN_ERROR; 4 } 5 jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V"); 6 if (methodId == NULL) { 7 return UNKNOWN_ERROR; 8 } 9 env->CallStaticVoidMethod(clazz, methodId);
以上几行的作用主要是调用init2这个函数,该函数定义在SystemServer.java文件中定义如下:
1 public static final void init2() { 2 Slog.i(TAG, "Entered the Android system server!"); 3 Thread thr = new ServerThread(); 4 thr.setName("android.server.ServerThread"); 5 thr.start(); 6 }
在以上的代码中开始执行这个线程,这个线程的本身定义在SystemServer.java这个文件中,定义如下:
1 class ServerThread extends Thread { 2 //... 3 4 @Override 5 public void run() { 6 //... 7 IPackageManager pm = null; 8 pm = PackageManagerService.main(context, installer, 9 factoryTest != SystemServer.FACTORY_TEST_OFF, 10 onlyCore); 11 boolean firstBoot = false; 12 try { 13 firstBoot = pm.isFirstBoot(); 14 } catch (RemoteException e) { 15 } 16 //... 27 }
在这个run函数中启动了android所需要的系统服务如PowerManagerService,ActivityManagerService 等系统服务,但是我们今天主要分析android的PackageManagerService。以上的函数调用定义在base/services/java/com/android/server/pm/PackageManagerService.java,定义如下:
public static final IPackageManager main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); ServiceManager.addService("package", m); return m; }
在该段代码中主要完成了向serviceManager的注册,其中PackageManagerService实现如下:
1 public PackageManagerService(Context context, Installer installer, 2 boolean factoryTest, boolean onlyCore) { 3 //... 4 File dataDir = Environment.getDataDirectory(); 5 mAppDataDir = new File(dataDir, "data"); 6 mAppInstallDir = new File(dataDir, "app"); 7 mAppLibInstallDir = new File(dataDir, "app-lib"); 8 mAsecInternalPath = new File(dataDir, "app-asec").getPath(); 9 mUserAppDataDir = new File(dataDir, "user"); 10 mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); 11 //... 12 mFrameworkInstallObserver = new AppDirObserver( 13 mFrameworkDir.getPath(), OBSERVER_EVENTS, true); 14 mFrameworkInstallObserver.startWatching(); 15 scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM 16 | PackageParser.PARSE_IS_SYSTEM_DIR, 17 scanMode | SCAN_NO_DEX, 0); 18 19 // Collect all system packages. 20 mSystemAppDir = new File(Environment.getRootDirectory(), "app"); 21 mSystemInstallObserver = new AppDirObserver( 22 mSystemAppDir.getPath(), OBSERVER_EVENTS, true); 23 mSystemInstallObserver.startWatching(); 24 scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM 25 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); 26 27 // Collect all vendor packages. 28 mVendorAppDir = new File("/vendor/app"); 29 mVendorInstallObserver = new AppDirObserver( 30 mVendorAppDir.getPath(), OBSERVER_EVENTS, true); 31 mVendorInstallObserver.startWatching(); 32 scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM 33 | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0); 34 //... 35 }
系统启动以后将搜索以下目录中的apk文件
/system/framework /system/app /vendor/app /data/app /data/app-private
搜索apk文件的函数主要由scanDirLI来实现,具体实现如下:
1 private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { 2 String[] files = dir.list(); 3 if (files == null) { 4 Log.d(TAG, "No files in app dir " + dir); 5 return; 6 } 7 8 if (DEBUG_PACKAGE_SCANNING) { 9 Log.d(TAG, "Scanning app dir " + dir); 10 } 11 12 int i; 13 for (i=0; i<files.length; i++) { 14 File file = new File(dir, files[i]); 15 if (!isPackageFilename(files[i])) { 16 // Ignore entries which are not apk's 17 continue; 18 } 19 PackageParser.Package pkg = scanPackageLI(file, 20 flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null); 21 // Don't mess around with apps in system partition. 22 if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 && 23 mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) { 24 // Delete the apk 25 Slog.w(TAG, "Cleaning up failed install of " + file); 26 file.delete(); 27 } 28 } 29 }
接下来我们看一下scanPackageLI这个函数,这个函数内容如下:
1 private PackageParser.Package scanPackageLI(File scanFile, 2 int parseFlags, int scanMode, long currentTime, UserHandle user) { 3 mLastScanError = PackageManager.INSTALL_SUCCEEDED; 4 String scanPath = scanFile.getPath(); 5 if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanPath); 6 parseFlags |= mDefParseFlags; 7 PackageParser pp = new PackageParser(scanPath); 8 pp.setSeparateProcesses(mSeparateProcesses); 9 pp.setOnlyCoreApps(mOnlyCore); 10 final PackageParser.Package pkg = pp.parsePackage(scanFile, 11 scanPath, mMetrics, parseFlags); 12 if (pkg == null) { 13 mLastScanError = pp.getParseError(); 14 return null; 15 } 16 PackageSetting ps = null; 17 PackageSetting updatedPkg; 18 //... 19 }
在这个函数中我们看到它调用一个新的对象PackageParser,这个对象定义在base/core/java/android/content/pm/PackageParser.java这个文件中,在这里我们主要看调用的parsePackage函数,该函数定义如下:
public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) { //... try { assmgr = new AssetManager(); int cookie = assmgr.addAssetPath(mArchiveSourcePath); if (cookie != 0) { res = new Resources(assmgr, metrics, null); assmgr.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); assetError = false; } else { Slog.w(TAG, "Failed adding asset path:"+mArchiveSourcePath); } } catch (Exception e) { Slog.w(TAG, "Unable to read AndroidManifest.xml of " + mArchiveSourcePath, e); } //...
该段代码主要用来解析Manifest文件。具体的代码此处不再分析,接着看下面的代码:
1 { 2 //... 3 Package pkg = null; 4 Exception errorException = null; 5 try { 6 // XXXX todo: need to figure out correct configuration. 7 pkg = parsePackage(res, parser, flags, errorText); 8 } catch (Exception e) { 9 errorException = e; 10 mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; 11 } 12 //... 13 }
从代码注释可以看出,此处主要是解析程序配置。接着我们回到scanPackageLI函数,接下来的代码如下:
1 synchronized (mPackages) { 2 3 String oldName = mSettings.mRenamedPackages.get(pkg.packageName); 4 if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) { 5 6 ps = mSettings.peekPackageLPr(oldName); 7 } 8 9 if (ps == null) { 10 ps = mSettings.peekPackageLPr(pkg.packageName); 11 } 12 13 updatedPkg = mSettings.getDisabledSystemPkgLPr(ps != null ? ps.name : pkg.packageName); 14 15 }
该段代码主要用来检查该包是否被重命名过,接下来看下面的内容:
1 { 2 //... 3 codePath = pkg.mScanPath; 4 setApplicationInfoPaths(pkg, codePath, resPath); 5 PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode 6 | SCAN_UPDATE_SIGNATURE, currentTime, user); 7 //... 8 }
在这里我们看一下scanPackageLI这个函数的另一个重载版本:
1 private PackageParser.Package scanPackageLI(PackageParser.Package pkg, 2 int parseFlags, int scanMode, long currentTime, UserHandle user) { 3 //... 4 5 // Check if we are renaming from an original package name. 6 PackageSetting origPackage = null; 7 String realName = null; 8 if (pkg.mOriginalPackages != null) { 9 final String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage); 10 if (pkg.mOriginalPackages.contains(renamed)) { 11 realName = pkg.mRealPackage; 12 if (!pkg.packageName.equals(renamed)) { 13 pkg.setPackageName(renamed); 14 } 15 16 } else { 17 18 for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) { 19 if ((origPackage = mSettings.peekPackageLPr( 20 pkg.mOriginalPackages.get(i))) != null) { 21 if (!verifyPackageUpdateLPr(origPackage, pkg)) { 22 origPackage = null; 23 continue; 24 } else if (origPackage.sharedUser != null) { 25 if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) { 26 Slog.w(TAG, "Unable to migrate data from " + origPackage.name 27 + " to " + pkg.packageName + ": old uid " 28 + origPackage.sharedUser.name 29 + " differs from " + pkg.mSharedUserId); 30 origPackage = null; 31 continue; 32 } 33 } else { 34 if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package " 35 + pkg.packageName + " to old name " + origPackage.name); 36 } 37 break; 38 } 39 } 40 } 41 } 42 43 //... 44 }
以上的代码主要用来检查一个包是否被重命名,如果该包重命名过,那在此处要负责把它替换过来。
adb 安装
这一部分的安装主要是开发者在开发app时使用adb来安装app,我们先看一下adb的实现,其中定义文件如下system/core/adb/adb.c,入口函数如下:
1 int main(int argc, char **argv) 2 { 3 #if ADB_HOST 4 adb_sysdeps_init(); 5 adb_trace_init(); 6 D("Handling commandline()\n"); 7 return adb_commandline(argc - 1, argv + 1); 8 #else 9 /* If adbd runs inside the emulator this will enable adb tracing via 10 * adb-debug qemud service in the emulator. */ 11 adb_qemu_trace_init(); 12 if((argc > 1) && (!strcmp(argv[1],"recovery"))) { 13 adb_device_banner = "recovery"; 14 recovery_mode = 1; 15 } 16 17 start_device_log(); 18 D("Handling main()\n"); 19 return adb_main(0, DEFAULT_ADB_PORT); 20 #endif 21 }
我们主要看一下adb_commandline的实现,该函数定义在system/core/adb/commandline.c文件中,整个函数的实现比叫多,我们只关心install的部分,所以我们只列出install的部分
1 int adb_commandline(int argc, char **argv) 2 { 3 //... 4 5 if(!strcmp(argv[0], "install")) { 6 if (argc < 2) return usage(); 7 return install_app(ttype, serial, argc, argv); 8 } 9 10 //... 11 }
我们找到install_app的实现,这个函数实现如下:
1 int install_app(transport_type transport, char* serial, int argc, char** argv) 2 { 3 static const char *const DATA_DEST = "/data/local/tmp/%s"; 4 static const char *const SD_DEST = "/sdcard/tmp/%s"; 5 const char* where = DATA_DEST; 6 //... 7 pm_command(transport, serial, argc, argv); 8 9 cleanup_apk: 10 if (verification_file != NULL) { 11 delete_file(transport, serial, verification_dest); 12 } 13 14 delete_file(transport, serial, apk_dest); 15 16 return err; 17 }
通过pm_command的处理我们已经将apk文件copy到了android的系统中,接下来我们看一下在android系统中到接到这一部分消息后是如何处理的。处理这一部分的代码定义在frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java文件中,我们找到对应install的部分代码定义如下:
1 public final class Pm { 2 IPackageManager mPm; 3 IUserManager mUm; 4 5 private WeakHashMap<String, Resources> mResourceCache 6 = new WeakHashMap<String, Resources>(); 7 8 private String[] mArgs; 9 private int mNextArg; 10 private String mCurArgData; 11 12 private static final String PM_NOT_RUNNING_ERR = 13 "Error: Could not access the Package Manager. Is the system running?"; 14 15 public static void main(String[] args) { 16 new Pm().run(args); 17 } 18 19 public void run(String[] args) { 20 boolean validCommand = false; 21 if (args.length < 1) { 22 showUsage(); 23 return; 24 } 25 26 mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user")); 27 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 28 29 //... 30 31 if ("install".equals(op)) { 32 runInstall(); 33 return; 34 } 35 36 //... 37 } 38 39 }
我们找到对应的runInstall的实现,定义如下:
1 private void runInstall() { 2 int installFlags = PackageManager.INSTALL_ALL_USERS; 3 String installerPackageName = null; 4 //... 5 6 PackageInstallObserver obs = new PackageInstallObserver(); 7 try { 8 VerificationParams verificationParams = new VerificationParams(verificationURI, 9 originatingURI, referrerURI, VerificationParams.NO_UID, null); 10 11 mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags, 12 installerPackageName, verificationParams, encryptionParams); 13 14 synchronized (obs) { 15 while (!obs.finished) { 16 try { 17 obs.wait(); 18 } catch (InterruptedException e) { 19 } 20 } 21 if (obs.result == PackageManager.INSTALL_SUCCEEDED) { 22 System.out.println("Success"); 23 } else { 24 System.err.println("Failure [" 25 + installFailureToString(obs.result) 26 + "]"); 27 } 28 } 29 } catch (RemoteException e) { 30 System.err.println(e.toString()); 31 System.err.println(PM_NOT_RUNNING_ERR); 32 } 33 34 //... 35 }
以上这一部分就是我们执行安装的部分,安装的过程是在PackageManager完成的,调用的函数为installPackageWithVerificationAndEncryption,该函数定义在PackageManager中,定义如下:
1 public void installPackageWithVerificationAndEncryption(Uri packageURI, 2 IPackageInstallObserver observer, int flags, String installerPackageName, 3 VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { 4 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, 5 null); 6 7 final int uid = Binder.getCallingUid(); 8 if (isUserRestricted(UserHandle.getUserId(uid), UserManager.DISALLOW_INSTALL_APPS)) { 9 try { 10 observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED); 11 } catch (RemoteException re) { 12 } 13 return; 14 } 15 16 UserHandle user; 17 if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) { 18 user = UserHandle.ALL; 19 } else { 20 user = new UserHandle(UserHandle.getUserId(uid)); 21 } 22 23 final int filteredFlags; 24 25 if (uid == Process.SHELL_UID || uid == 0) { 26 if (DEBUG_INSTALL) { 27 Slog.v(TAG, "Install from ADB"); 28 } 29 filteredFlags = flags | PackageManager.INSTALL_FROM_ADB; 30 } else { 31 filteredFlags = flags & ~PackageManager.INSTALL_FROM_ADB; 32 } 33 34 verificationParams.setInstallerUid(uid); 35 36 final Message msg = mHandler.obtainMessage(INIT_COPY); 37 msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, 38 verificationParams, encryptionParams, user); 39 mHandler.sendMessage(msg); 40 }
以上就是通过adb安装的过程了。需要说明的是这一部分的安装是没有界面的。
通过安装器安装:
一般的用户安装程序,可能接触到做多的就是这个了,下面就介绍一下通过安装器安装的流程。其中系统默认的安装器源码路径为:packages/apps/PackageInstaller/,下面我分析一下其实现,这个就是一个普通的android app应用,其入口文件为:PackageInstallerActivity.java,其中onCreate函数定义如下:
1 protected void onCreate(Bundle icicle) { 2 super.onCreate(icicle); 3 4 // get intent information 5 final Intent intent = getIntent(); 6 mPackageURI = intent.getData(); 7 mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); 8 mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER); 9 mPm = getPackageManager(); 10 11 final String scheme = mPackageURI.getScheme(); 12 if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { 13 Log.w(TAG, "Unsupported scheme " + scheme); 14 setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); 15 return; 16 } 17 18 final PackageUtil.AppSnippet as; 19 if ("package".equals(mPackageURI.getScheme())) { 20 try { 21 mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(), 22 PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); 23 } catch (NameNotFoundException e) { 24 } 25 if (mPkgInfo == null) { 26 Log.w(TAG, "Requested package " + mPackageURI.getScheme() 27 + " not available. Discontinuing installation"); 28 showDialogInner(DLG_PACKAGE_ERROR); 29 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); 30 return; 31 } 32 as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), 33 mPm.getApplicationIcon(mPkgInfo.applicationInfo)); 34 } else { 35 final File sourceFile = new File(mPackageURI.getPath()); 36 PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile); 37 38 // Check for parse errors 39 if (parsed == null) { 40 Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); 41 showDialogInner(DLG_PACKAGE_ERROR); 42 setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); 43 return; 44 } 45 mPkgInfo = PackageParser.generatePackageInfo(parsed, null, 46 PackageManager.GET_PERMISSIONS, 0, 0, null, 47 new PackageUserState()); 48 mPkgDigest = parsed.manifestDigest; 49 as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); 50 }
这一部分就比较简单了,首先根据intent获取传递的信息,之后调用PakcageManager的函数获取apk文件的信息,当用户点击安装时进行安装,其最终调用的函数为:
1 if ("package".equals(mPackageURI.getScheme())) { 2 try { 3 pm.installExistingPackage(mAppInfo.packageName); 4 observer.packageInstalled(mAppInfo.packageName, 5 PackageManager.INSTALL_SUCCEEDED); 6 } catch (PackageManager.NameNotFoundException e) { 7 observer.packageInstalled(mAppInfo.packageName, 8 PackageManager.INSTALL_FAILED_INVALID_APK); 9 } 10 } else { 11 pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags, 12 installerPackageName, verificationParams, null); 13 }
可以看到在此处做了一个判断,这个包是否已经被安装过了,两者调用了不同的函数。installExistingPackage函数定义在frameworks/base/core/java/android/app/ApplicationPackageManager.java文件中,实现如下:
1 public int installExistingPackage(String packageName) 2 throws NameNotFoundException { 3 try { 4 int res = mPM.installExistingPackageAsUser(packageName, UserHandle.myUserId()); 5 if (res == INSTALL_FAILED_INVALID_URI) { 6 throw new NameNotFoundException("Package " + packageName + " doesn't exist"); 7 } 8 return res; 9 } catch (RemoteException e) { 10 // Should never happen! 11 throw new NameNotFoundException("Package " + packageName + " doesn't exist"); 12 } 13 }
可以看到其最终调用了PackageManager的installExistingPackageAsUser函数。installPackageWithVerificationAndEncryption也定义frameworks/base/core/java/android/app/ApplicationPackageManager.java文件中,实现如下:
1 public void installPackageWithVerificationAndEncryption(Uri packageURI, 2 IPackageInstallObserver observer, int flags, String installerPackageName, 3 VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { 4 try { 5 mPM.installPackageWithVerificationAndEncryption(packageURI, observer, flags, 6 installerPackageName, verificationParams, encryptionParams); 7 } catch (RemoteException e) { 8 // Should never happen! 9 } 10 }
其最终调用了PackageManager的installPackageWithVerificationAndEncryption函数。以上就是通过安装器安装的过程。