android 应用程序安装源码分析

2024-05-15 20:48

本文主要是介绍android 应用程序安装源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在本章开始之前,我们应该都安装过应用。

每次安装应用的出发点都是有一个检查权限的弹框,那么我们就冲这个弹框入手.

安装应用一定首先要把apk的路径传过来,

系统安装应用信息如下:

act=android.intent.action.VIEW 

dat=file:///storage/emulated/0/activityTest.apk 

typ=application/vnd.android.package-archive 

flg=0x17000000 

cmp=com.android.packageinstaller/.PackageInstallerActivity

Step 1 : PackageInstallerActivity.java


    protected void onCreate(Bundle icicle) {super.onCreate(icicle);mPm = getPackageManager();mInstaller = mPm.getPackageInstaller();mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);final Intent intent = getIntent();if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
//5.1的原生是没有检查permission的} else {mSessionId = -1;mPackageURI = intent.getData();                  //这里获取到安装包的Uri路径mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);}final String scheme = mPackageURI.getScheme();......final PackageUtil.AppSnippet as;if ("package".equals(mPackageURI.getScheme())) {mInstallFlowAnalytics.setFileUri(false);try {mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);} catch (NameNotFoundException e) {}if (mPkgInfo == null) {Log.w(TAG, "Requested package " + mPackageURI.getScheme()+ " not available. Discontinuing installation");showDialogInner(DLG_PACKAGE_ERROR);setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);mInstallFlowAnalytics.setPackageInfoObtained();mInstallFlowAnalytics.setFlowFinished(InstallFlowAnalytics.RESULT_FAILED_PACKAGE_MISSING);return;}as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),mPm.getApplicationIcon(mPkgInfo.applicationInfo));} else {mInstallFlowAnalytics.setFileUri(true);final File sourceFile = new File(mPackageURI.getPath());                         //拿到文件PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);           //解析,这里其实就已经拿到了Apk的所有信息了,包括resource里面的所有资源,由于这里拿只是为了显示,所以后面还会不断的来拿这些信息mPkgInfo = PackageParser.generatePackageInfo(parsed, null,                       //拿到整个安装包的信息PackageManager.GET_PERMISSIONS, 0, 0, null,new PackageUserState());mPkgDigest = parsed.manifestDigest;as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);      //这里只是提取icon和lable供我们显示使用}.....}


Step 2 :  PackageInstallerActivity.java     //当可以安装的时候,我们点击确定流程如下:

    public void onClick(View v) {if (v == mOk) {if (mOkCanInstall || mScrollView == null) {mInstallFlowAnalytics.setInstallButtonClicked();if (mSessionId != -1) {                             mInstaller.setPermissionsResult(mSessionId, true);// We're only confirming permissions, so we don't really know how the// story ends; assume success.mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult(PackageManager.INSTALL_SUCCEEDED);} else {// Start subactivity to actually install the applicationIntent newIntent = new Intent();newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,mPkgInfo.applicationInfo);      //将applicationInfo传过去,这个里面有apk的信息newIntent.setData(mPackageURI);        //路径穿过去,这个apk的路径是整个流程的关键。newIntent.setClass(this, InstallAppProgress.class);newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);newIntent.putExtra(InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);if (mOriginatingURI != null) {newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);}if (mReferrerURI != null) {newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);}if (mOriginatingUid != VerificationParams.NO_UID) {newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);}if (installerPackageName != null) {newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,installerPackageName);}if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);}if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);startActivity(newIntent);         //从这里我们可以看到,我们会将所有有用的信息都传给InstallAppProgress的Activity,来进行下一步操作。}finish();} else {mScrollView.pageScroll(View.FOCUS_DOWN);}} else if(v == mCancel) {// Cancel and finishsetResult(RESULT_CANCELED);if (mSessionId != -1) {mInstaller.setPermissionsResult(mSessionId, false);}mInstallFlowAnalytics.setFlowFinished(InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);finish();}}

Step 3 : InstallAppProgress.java

    public void onCreate(Bundle icicle) {super.onCreate(icicle);Intent intent = getIntent();mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);mInstallFlowAnalytics = intent.getParcelableExtra(EXTRA_INSTALL_FLOW_ANALYTICS);mInstallFlowAnalytics.setContext(this);mPackageURI = intent.getData();           //这里时apk的路径final String scheme = mPackageURI.getScheme();if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {mInstallFlowAnalytics.setFlowFinished(InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME);throw new IllegalArgumentException("unexpected scheme " + scheme);}initView();}


Step 4 : InstallAppProgress.java

    public void initView() {
......//中间的一些view的初始化与数据的获取if ("package".equals(mPackageURI.getScheme())) {try {pm.installExistingPackage(mAppInfo.packageName);observer.packageInstalled(mAppInfo.packageName,PackageManager.INSTALL_SUCCEEDED);} catch (PackageManager.NameNotFoundException e) {observer.packageInstalled(mAppInfo.packageName,PackageManager.INSTALL_FAILED_INVALID_APK);}} else {pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,installerPackageName, verificationParams, null);                          //这里进行安装apk的地方}}


Step 5 : ApplicationPackageManager.java

    public void installPackageWithVerificationAndEncryption(Uri packageURI,PackageInstallObserver observer, int flags, String installerPackageName,VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {installCommon(packageURI, observer, flags, installerPackageName, verificationParams,encryptionParams);}


    private void installCommon(Uri packageURI,PackageInstallObserver observer, int flags, String installerPackageName,VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {if (!"file".equals(packageURI.getScheme())) {throw new UnsupportedOperationException("Only file:// URIs are supported");}if (encryptionParams != null) {throw new UnsupportedOperationException("ContainerEncryptionParams not supported");}final String originPath = packageURI.getPath();try {mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,verificationParams, null);               } catch (RemoteException ignored) {}}

Step 6 : PackageManagerService.java

    public void installPackage(String originPath, IPackageInstallObserver2 observer,int installFlags, String installerPackageName, VerificationParams verificationParams,String packageAbiOverride) {installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,packageAbiOverride, UserHandle.getCallingUserId());}

    public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,int installFlags, String installerPackageName, VerificationParams verificationParams,String packageAbiOverride, int userId) {mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);final int callingUid = Binder.getCallingUid();enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {      //多用户权限管理try {if (observer != null) {observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);}} catch (RemoteException re) {}return;}if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {installFlags |= PackageManager.INSTALL_FROM_ADB;     //adb 安装流程与正式流程分开} else {// Caller holds INSTALL_PACKAGES permission, so we're less strict// about installerPackageName.installFlags &= ~PackageManager.INSTALL_FROM_ADB;installFlags &= ~PackageManager.INSTALL_ALL_USERS;}UserHandle user;if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {user = UserHandle.ALL;} else {user = new UserHandle(userId);}verificationParams.setInstallerUid(callingUid);final File originFile = new File(originPath);final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);final Message msg = mHandler.obtainMessage(INIT_COPY);msg.obj = new InstallParams(origin, observer, installFlags,installerPackageName, verificationParams, user, packageAbiOverride);mHandler.sendMessage(msg);            //这里将信息放到InstallParams里,通过Handler来依次执行操作。}


Step 7 : PackageManagerService$PackageHandler

        public void handleMessage(Message msg) {try {doHandleMessage(msg);} finally {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);}}
执行INIT_COPY 消息。
        void doHandleMessage(Message msg) {switch (msg.what) {case INIT_COPY: {HandlerParams params = (HandlerParams) msg.obj;        //这个的类型是InstallParams在Step 6中可以看到int idx = mPendingInstalls.size();if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params);// If a bind was already initiated we dont really// need to do anything. The pending install// will be processed later on.if (!mBound) {                    //这个值是在connectToService()中设置为true的,这里做的就是初始化server// If this is the only one pending we might// have to bind to the service again.if (!connectToService()) {Slog.e(TAG, "Failed to bind to media container service");params.serviceError();return;} else {// Once we bind to the service, the first// pending request will be processed.mPendingInstalls.add(idx, params);                                       //这里放进去的信息,之后就等待service绑定成功之后,我们进行下一步操作。}} else {mPendingInstalls.add(idx, params);// Already bound to the service. Just make// sure we trigger off processing the first request.if (idx == 0) {mHandler.sendEmptyMessage(MCS_BOUND);    //可以看到如果已经连接成功,并且是第一个数据,(这种情况是很少会发生的,这里应该只是为了容错处理,正常的流程是在Step 8中)直接进行下一步}}break;}
        private boolean connectToService() {if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to bind to" +" DefaultContainerService");Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);if (mContext.bindServiceAsUser(service, mDefContainerConn,                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {                         //在连接的时候,这个service并没有做什么,只是一个启动和bind的过程。Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);mBound = true;return true;}Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);return false;}

Step 8 :PackageManagerService$PackageHandler

下面我们来看绑定service成功的时候,

    final private DefaultContainerConnection mDefContainerConn =new DefaultContainerConnection();class DefaultContainerConnection implements ServiceConnection {public void onServiceConnected(ComponentName name, IBinder service) {if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceConnected");IMediaContainerService imcs =IMediaContainerService.Stub.asInterface(service);mHandler.sendMessage(mHandler.obtainMessage(MCS_BOUND, imcs));                           //这里是常规的进行下一步操作的地方。Bound里是操作的地方,继续跟踪就会发现每次执行完mPendingInstalls里的所有事件之后,就会unbind这个service,}public void onServiceDisconnected(ComponentName name) {if (DEBUG_SD_INSTALL) Log.i(TAG, "onServiceDisconnected");}};

Step 9 :PackageManagerService$PackageHandler

        void doHandleMessage(Message msg) {switch (msg.what) {case MCS_BOUND: {if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");if (msg.obj != null) {                                             //这个是在Step 8中传过来的,所以正常情况肯定是不会是null的mContainerService = (IMediaContainerService) msg.obj;                      }if (mContainerService == null) {// Something seriously wrong. Bail outSlog.e(TAG, "Cannot bind to media container service");for (HandlerParams params : mPendingInstalls) {                     // Indicate service bind errorparams.serviceError();}mPendingInstalls.clear();} else if (mPendingInstalls.size() > 0) {HandlerParams params = mPendingInstalls.get(0);                //在Step 6中我们可以知道,这个是InstallParams类型。if (params != null) {if (params.startCopy()) {                                   // We are done...  look for more work or to// go idle.if (DEBUG_SD_INSTALL) Log.i(TAG,"Checking for more work or unbind...");// Delete pending installif (mPendingInstalls.size() > 0) {mPendingInstalls.remove(0);}if (mPendingInstalls.size() == 0) {if (mBound) {if (DEBUG_SD_INSTALL) Log.i(TAG,"Posting delayed MCS_UNBIND");removeMessages(MCS_UNBIND);Message ubmsg = obtainMessage(MCS_UNBIND);// Unbind after a little delay, to avoid// continual thrashing.sendMessageDelayed(ubmsg, 10000);}} else {// There are more pending requests in queue.// Just post MCS_BOUND message to trigger processing// of next pending install.if (DEBUG_SD_INSTALL) Log.i(TAG,"Posting MCS_BOUND for next work");mHandler.sendEmptyMessage(MCS_BOUND);}}}} else {// Should never happen ideally.Slog.w(TAG, "Empty queue");}break;}

 private abstract class HandlerParams {final boolean startCopy() {                //进入到父类的方法中,boolean res;try {if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);if (++mRetries > MAX_RETRIES) {Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");mHandler.sendEmptyMessage(MCS_GIVE_UP);handleServiceError();return false;} else {handleStartCopy();                //调回到InstallParamsres = true;}} catch (RemoteException e) {if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");mHandler.sendEmptyMessage(MCS_RECONNECT);res = false;}handleReturnCode();                        //到Step 22中查看。return res;}}

Step 10 :PackageManagerService$InstallParams

        public void handleStartCopy() throws RemoteException {.....//省略的是一些权限检查与if(mInstaller.freeCache()){}这里是通过socket连接到installd的驱动进行释放cache的,保证我们可以正常安装......final InstallArgs args = createInstallArgs(this);               //这里是在Step 11中创建的,这里如果不是安装在sd卡上的话,则会返回FileInstallArgsmArgs = args;if (ret == PackageManager.INSTALL_SUCCEEDED) {......                                                 //这里则是针对所将要发送的广播做一些数据的填充。而且在这里又一次调用了PackageParse解析apk,这里不再重复了,final PackageVerificationState verificationState = new PackageVerificationState(requiredUid, args);                            //这里将我们的args放入mPendingVerification中,在Step 12中会取出使用mPendingVerification.append(verificationId, verificationState);........if (ret == PackageManager.INSTALL_SUCCEEDED&& mRequiredVerifierPackage != null) {/** Send the intent to the required verification agent,* but only start the verification timeout after the* target BroadcastReceivers have run.*/verification.setComponent(requiredVerifierComponent);mContext.sendOrderedBroadcastAsUser(verification, getUser(),android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {final Message msg = mHandler.obtainMessage(CHECK_PENDING_VERIFICATION);msg.arg1 = verificationId;mHandler.sendMessageDelayed(msg, getVerificationTimeout());//当广播被接收之后,会发送消息出去。放出去之后,进入到Step 12中}}, null, 0, null, null);/** We don't want the copy to proceed until verification* succeeds, so null out this field.*/mArgs = null;}} else {/** No package verification is enabled, so immediately start* the remote call to initiate copy using temporary file.*/ret = args.copyApk(mContainerService, true);}}mRet = ret;}


Step 11 : PackageManagerService$InstallParams
    private InstallArgs createInstallArgs(InstallParams params) {if (installOnSd(params.installFlags) || params.isForwardLocked()) {return new AsecInstallArgs(params);} else {return new FileInstallArgs(params);}}
Step 12 : PackageManagerService$PackageHandler

                case CHECK_PENDING_VERIFICATION: {final int verificationId = msg.arg1;final PackageVerificationState state = mPendingVerification.get(verificationId);if ((state != null) && !state.timeoutExtended()) {final InstallArgs args = state.getInstallArgs();                     //这里取出Step 11中放入的值,final Uri originUri = Uri.fromFile(args.origin.resolvedFile);Slog.i(TAG, "Verification timed out for " + originUri);mPendingVerification.remove(verificationId);int ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;if (getDefaultVerificationResponse() == PackageManager.VERIFICATION_ALLOW) {Slog.i(TAG, "Continuing with installation of " + originUri);state.setVerifierResponse(Binder.getCallingUid(),PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT);broadcastPackageVerified(verificationId, originUri,PackageManager.VERIFICATION_ALLOW,state.getInstallArgs().getUser());try {ret = args.copyApk(mContainerService, true);                       //这里是开始复制apk的过程,之前已经检查过,这个} catch (RemoteException e) {Slog.e(TAG, "Could not contact the ContainerService");}} else {broadcastPackageVerified(verificationId, originUri,PackageManager.VERIFICATION_REJECT,state.getInstallArgs().getUser());}processPendingInstall(args, ret);mHandler.sendEmptyMessage(MCS_UNBIND);}break;}
Step 13 : PackageManagerService$FileInstallArgs
        int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {if (origin.staged) {Slog.d(TAG, origin.file + " already staged; skipping copy");codeFile = origin.file;resourceFile = origin.file;return PackageManager.INSTALL_SUCCEEDED;}try {final File tempDir = mInstallerService.allocateInternalStageDirLegacy();                      //这里就是获取路径的地方。//data/app/vmdl***.tmp这里在 5.1是一个废弃的接口,所以这里有点疑惑,如果哪位发现这里的流程有问题,请及时沟通。这里建立的时候权限是755后面会改成644.codeFile = tempDir;                                                                          //这里copyFile很重要,以后的文件都会拷贝到这里。resourceFile = tempDir;} catch (IOException e) {Slog.w(TAG, "Failed to create copy file: " + e);return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;}final IParcelFileDescriptorFactory target = new IParcelFileDescriptorFactory.Stub() {              //这个将会在Step 15中回调使用。@Overridepublic ParcelFileDescriptor open(String name, int mode) throws RemoteException {               //在Step15中可以知道这个name : base.apkif (!FileUtils.isValidExtFilename(name)) {throw new IllegalArgumentException("Invalid filename: " + name);}try {final File file = new File(codeFile, name);final FileDescriptor fd = Os.open(file.getAbsolutePath(),O_RDWR | O_CREAT, 0644);Os.chmod(file.getAbsolutePath(), 0644);return new ParcelFileDescriptor(fd);} catch (ErrnoException e) {throw new RemoteException("Failed to open: " + e.getMessage());}}};int ret = PackageManager.INSTALL_SUCCEEDED;ret = imcs.copyPackage(origin.file.getAbsolutePath(), target);                                  // 进入到Step 14中,if (ret != PackageManager.INSTALL_SUCCEEDED) {Slog.e(TAG, "Failed to copy package");return ret;}final File libraryRoot = new File(codeFile, LIB_DIR_NAME);NativeLibraryHelper.Handle handle = null;try {handle = NativeLibraryHelper.Handle.create(codeFile);ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,abiOverride);} catch (IOException e) {                                                //这里是拷贝.so到lib文件夹,并且会根据不同cpu来建立不同文件夹Slog.e(TAG, "Copying native libraries failed", e);ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;} finally {IoUtils.closeQuietly(handle);}return ret;}
Step 13.1 : PackageInstallerService.java
    public File allocateInternalStageDirLegacy() throws IOException {synchronized (mSessions) {try {final int sessionId = allocateSessionIdLocked();mLegacySessions.put(sessionId, true);final File stageDir = buildInternalStageDir(sessionId);prepareInternalStageDir(stageDir);return stageDir;} catch (IllegalStateException e) {throw new IOException(e);}}}
    private File buildInternalStageDir(int sessionId) {return new File(mStagingDir, "vmdl" + sessionId + ".tmp");}


Step 14 :DefaultContainerService.java
        @Overridepublic int copyPackage(String packagePath, IParcelFileDescriptorFactory target) {if (packagePath == null || target == null) {return PackageManager.INSTALL_FAILED_INVALID_URI;}PackageLite pkg = null;try {final File packageFile = new File(packagePath);pkg = PackageParser.parsePackageLite(packageFile, 0);                  //这里很重要,这里已经是第三次解析了,请看Step 16:return copyPackageInner(pkg, target);} catch (PackageParserException | IOException | RemoteException e) {Slog.w(TAG, "Failed to copy package at " + packagePath + ": " + e);return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;}}


Step 15 : DefaultContainerService.java
    private int copyPackageInner(PackageLite pkg, IParcelFileDescriptorFactory target)throws IOException, RemoteException {copyFile(pkg.baseCodePath, target, "base.apk");if (!ArrayUtils.isEmpty(pkg.splitNames)) {                            //从Step 16中,我们可以知道,这里返回的splitNames是null的,所以不会进入这里,for (int i = 0; i < pkg.splitNames.length; i++) {copyFile(pkg.splitCodePaths[i], target, "split_" + pkg.splitNames[i] + ".apk");}}return PackageManager.INSTALL_SUCCEEDED;}
    private void copyFile(String sourcePath, IParcelFileDescriptorFactory target, String targetName)throws IOException, RemoteException {Slog.d(TAG, "Copying " + sourcePath + " to " + targetName);InputStream in = null;OutputStream out = null;try {in = new FileInputStream(sourcePath);out = new ParcelFileDescriptor.AutoCloseOutputStream(target.open(targetName, ParcelFileDescriptor.MODE_READ_WRITE));Streams.copy(in, out);          //可以看到这里是将apk拷贝到临时文件里:/data/app/vmdl***.tmp/base.apk</span>} finally {IoUtils.closeQuietly(out);IoUtils.closeQuietly(in);}}



Step 16 : PackageParser.java

    public static PackageLite parsePackageLite(File packageFile, int flags)throws PackageParserException {if (packageFile.isDirectory()) {                         //这里会看是否是路径,我们解析apk的时候,传的都是文件。return parseClusterPackageLite(packageFile, flags);} else {return parseMonolithicPackageLite(packageFile, flags);}}

    private static PackageLite parseMonolithicPackageLite(File packageFile, int flags)throws PackageParserException {final ApkLite baseApk = parseApkLite(packageFile, flags);final String packagePath = packageFile.getAbsolutePath();return new PackageLite(packagePath, baseApk, null, null, null);//baseApk相当于一个轻量级的apk信息实例,这里就相当于比轻量级略多信息的实例了,}
Step 17 : PackageParser.java
    public static ApkLite parseApkLite(File apkFile, int flags)throws PackageParserException {final String apkPath = apkFile.getAbsolutePath();AssetManager assets = null;XmlResourceParser parser = null;try {assets = new AssetManager();assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,Build.VERSION.RESOURCES_SDK_INT);int cookie = assets.addAssetPath(apkPath);                  //这里是将apk的path添加到AssetManager中.if (cookie == 0) {throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,"Failed to parse " + apkPath);}final DisplayMetrics metrics = new DisplayMetrics();metrics.setToDefaults();final Resources res = new Resources(assets, metrics, null);               //这里将asset放到Resources中,我们知道所有的资源文件都是通过资源文件获取到的,这个返回的res其实就可以拿到我们的所有资源了,//R.layout.xxxx;parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); //这里会解析AndroidManifest,由于AssetManager的大部分方法都是在Native中完成,请参考Step 18。这里返回的parse拥有AndroidManifest中的解析信息。final Signature[] signatures;if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {// TODO: factor signature related items out of Package objectfinal Package tempPkg = new Package(null);collectCertificates(tempPkg, apkFile, 0);                             //这里是证书认证的地方。signatures = tempPkg.mSignatures;} else {signatures = null;}final AttributeSet attrs = parser;return parseApkLite(apkPath, res, parser, attrs, flags, signatures);      //Step 20 中获取返回满载信息的ApkLite对象} catch (XmlPullParserException | IOException | RuntimeException e) {throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,"Failed to parse " + apkPath, e);} finally {IoUtils.closeQuietly(parser);IoUtils.closeQuietly(assets);}}
Step 18 : AssetManager.java
    public final XmlResourceParser openXmlResourceParser(int cookie,String fileName) throws IOException {XmlBlock block = openXmlBlockAsset(cookie, fileName);XmlResourceParser rp = block.newParser();block.close();return rp;}

    /*package*/ final XmlBlock openXmlBlockAsset(String fileName)throws IOException {return openXmlBlockAsset(0, fileName);}
    /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName)throws IOException {synchronized (this) {if (!mOpen) {throw new RuntimeException("Assetmanager has been closed");}long xmlBlock = openXmlAssetNative(cookie, fileName);if (xmlBlock != 0) {XmlBlock res = new XmlBlock(this, xmlBlock);incRefsLocked(res.hashCode());return res;}}throw new FileNotFoundException("Asset XML file: " + fileName);}
Step 19 : android_util_AssetManager.cpp
static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,jint cookie,jstring fileName)
{AssetManager* am = assetManagerForJavaObject(env, clazz);if (am == NULL) {return 0;}ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);ScopedUtfChars fileName8(env, fileName);if (fileName8.c_str() == NULL) {return 0;}int32_t assetCookie = static_cast<int32_t>(cookie);Asset* a = assetCookie? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER): am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);if (a == NULL) {jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());return 0;}const DynamicRefTable* dynamicRefTable =am->getResources().getDynamicRefTableForCookie(assetCookie);ResXMLTree* block = new ResXMLTree(dynamicRefTable);status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);a->close();delete a;if (err != NO_ERROR) {jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");return 0;}return reinterpret_cast<jlong>(block);
}

 Step 20 : PackageParser.java
    private static ApkLite parseApkLite(String codePath, Resources res, XmlPullParser parser,AttributeSet attrs, int flags, Signature[] signatures) throws IOException,XmlPullParserException, PackageParserException {final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags);int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;int versionCode = 0;int revisionCode = 0;boolean coreApp = false;boolean multiArch = false;for (int i = 0; i < attrs.getAttributeCount(); i++) {final String attr = attrs.getAttributeName(i);if (attr.equals("installLocation")) {installLocation = attrs.getAttributeIntValue(i,PARSE_DEFAULT_INSTALL_LOCATION);} else if (attr.equals("versionCode")) {versionCode = attrs.getAttributeIntValue(i, 0);} else if (attr.equals("revisionCode")) {revisionCode = attrs.getAttributeIntValue(i, 0);} else if (attr.equals("coreApp")) {coreApp = attrs.getAttributeBooleanValue(i, false);}}// Only search the tree when the tag is directly below <manifest>int type;final int searchDepth = parser.getDepth() + 1;final List<VerifierInfo> verifiers = new ArrayList<VerifierInfo>();while ((type = parser.next()) != XmlPullParser.END_DOCUMENT&& (type != XmlPullParser.END_TAG || parser.getDepth() >= searchDepth)) {if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {continue;}if (parser.getDepth() == searchDepth && "package-verifier".equals(parser.getName())) {final VerifierInfo verifier = parseVerifier(res, parser, attrs, flags);            //这里是key的解析if (verifier != null) {verifiers.add(verifier);}}if (parser.getDepth() == searchDepth && "application".equals(parser.getName())) {for (int i = 0; i < attrs.getAttributeCount(); ++i) {final String attr = attrs.getAttributeName(i);if ("multiArch".equals(attr)) {multiArch = attrs.getAttributeBooleanValue(i, false);break;}}}}return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,revisionCode, installLocation, verifiers, signatures, coreApp, multiArch);}

Step 21 :PackageParser$ApkLite
    public static class ApkLite {public final String codePath;public final String packageName;public final String splitName;public final int versionCode;public final int revisionCode;public final int installLocation;public final VerifierInfo[] verifiers;public final Signature[] signatures;public final boolean coreApp;public final boolean multiArch;public ApkLite(String codePath, String packageName, String splitName, int versionCode,int revisionCode, int installLocation, List<VerifierInfo> verifiers,Signature[] signatures, boolean coreApp, boolean multiArch) {this.codePath = codePath;this.packageName = packageName;this.splitName = splitName;this.versionCode = versionCode;this.revisionCode = revisionCode;this.installLocation = installLocation;this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);this.signatures = signatures;this.coreApp = coreApp;this.multiArch = multiArch;}}
到这里我们已经对整个apk的拷贝过程基本了解里,下面我们在回到Step 9中,看看拷贝之后做了哪些事情。
Step 22 : PackageManagerService.java$
InstallParams

        @Overridevoid handleReturnCode() {// If mArgs is null, then MCS couldn't be reached. When it// reconnects, it will try again to install. At that point, this// will succeed.if (mArgs != null) {                                //这个是在Step 10中赋值的,FileInstallArgs</span>processPendingInstall(mArgs, mRet);}}

Step 23:PackageManagerService.java
    private void processPendingInstall(final InstallArgs args, final int currentStatus) {// Queue up an async operation since the package installation may take a little while.mHandler.post(new Runnable() {public void run() {mHandler.removeCallbacks(this);// Result object to be returnedPackageInstalledInfo res = new PackageInstalledInfo();res.returnCode = currentStatus;res.uid = -1;res.pkg = null;res.removedInfo = new PackageRemovedInfo();if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {args.doPreInstall(res.returnCode);                                 //这里是一个如果失败了的话,会进行clean的操作,会将刚才的/data/app/vmdl***.tmp文件夹及下面的文件删掉.synchronized (mInstallLock) {installPackageLI(args, res);                                   //进入Step 24}args.doPostInstall(res.returnCode, res.uid);}// A restore should be performed at this point if (a) the install// succeeded, (b) the operation is not an update, and (c) the new// package has not opted out of backup participation.final boolean update = res.removedInfo.removedPackage != null;final int flags = (res.pkg == null) ? 0 : res.pkg.applicationInfo.flags;boolean doRestore = !update&& ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0);// Set up the post-install work request bookkeeping.  This will be used// and cleaned up by the post-install event handling regardless of whether// there's a restore pass performed.  Token values are >= 1.int token;if (mNextInstallToken < 0) mNextInstallToken = 1;token = mNextInstallToken++;PostInstallData data = new PostInstallData(args, res);mRunningInstalls.put(token, data);if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);if (res.returnCode == PackageManager.INSTALL_SUCCEEDED && doRestore) {// Pass responsibility to the Backup Manager.  It will perform a// restore if appropriate, then pass responsibility back to the// Package Manager to run the post-install observer callbacks// and broadcasts.IBackupManager bm = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));if (bm != null) {if (DEBUG_INSTALL) Log.v(TAG, "token " + token+ " to BM for possible restore");try {if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) {bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);} else {doRestore = false;}} catch (RemoteException e) {// can't happen; the backup manager is local} catch (Exception e) {Slog.e(TAG, "Exception trying to enqueue restore", e);doRestore = false;}} else {Slog.e(TAG, "Backup Manager not found!");doRestore = false;}}if (!doRestore) {// No restore possible, or the Backup Manager was mysteriously not// available -- just fire the post-install work request directly.if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);mHandler.sendMessage(msg);}}});}

Step 24:PackageManagerService.java

    private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {final int installFlags = args.installFlags;String installerPackageName = args.installerPackageName;File tmpPackageFile = new File(args.getCodePath());boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);boolean replace = false;final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;// Result object to be returnedres.returnCode = PackageManager.INSTALL_SUCCEEDED;if (DEBUG_INSTALL) Slog.d(TAG, "installPackageLI: path=" + tmpPackageFile);// Retrieve PackageSettings and parse packagefinal int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)| (onSd ? PackageParser.PARSE_ON_SDCARD : 0);PackageParser pp = new PackageParser();pp.setSeparateProcesses(mSeparateProcesses);pp.setDisplayMetrics(mMetrics);final PackageParser.Package pkg;try {pkg = pp.parsePackage(tmpPackageFile, parseFlags);                     //这里第四次解析,但这次和在Step 14中有区别的,这个tmpPackageFile是个path,流程不同而已,最终还是一条路.} catch (PackageParserException e) {res.setError("Failed parse during installPackageLI", e);return;}//中间的权限检查,版本升级流程等信息省略.....if (!args.doRename(res.returnCode, pkg, oldCodePath)) {                 //这个命名规则很简单暴力,看Step 25res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");return;}if (replace) {							//如果覆盖安装、升级走replace,新安装走下面的。replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,installerPackageName, res);} else {installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,                      //进入step 27args.user, installerPackageName, res);}synchronized (mPackages) {final PackageSetting ps = mSettings.mPackages.get(pkgName);if (ps != null) {res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);}}}

Step 25 :PackageManagerService.java$FileInstallArgs

        boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {if (status != PackageManager.INSTALL_SUCCEEDED) {cleanUp();return false;} else {final File beforeCodeFile = codeFile;final File afterCodeFile = getNextCodePath(pkg.packageName);              //从Step 26中可以看到,这里返回的就是packagename-n.apk这个n是从1一直加的知道文件不存在。Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);try {Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());              //改完之后,就变成了packagename-n.apk</span>} catch (ErrnoException e) {Slog.d(TAG, "Failed to rename", e);return false;}if (!SELinux.restoreconRecursive(afterCodeFile)) {Slog.d(TAG, "Failed to restorecon");return false;}// Reflect the rename internallycodeFile = afterCodeFile;resourceFile = afterCodeFile;// Reflect the rename in scanned detailspkg.codePath = afterCodeFile.getAbsolutePath();pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,pkg.baseCodePath);pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,pkg.splitCodePaths);// Reflect the rename in app infopkg.applicationInfo.setCodePath(pkg.codePath);pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);pkg.applicationInfo.setResourcePath(pkg.codePath);pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);return true;}}
Step 26 : PackageManagerService.java$FileInstallArgs
    private File getNextCodePath(String packageName) {int suffix = 1;File result;do {result = new File(mAppInstallDir, packageName + "-" + suffix);suffix++;} while (result.exists());return result;}
Step 27 : PackageManagerService.java

    private void installNewPackageLI(PackageParser.Package pkg,int parseFlags, int scanFlags, UserHandle user,String installerPackageName, PackageInstalledInfo res) {// Remember this for later, in case we need to rollback this installString pkgName = pkg.packageName;if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists();     //这个获取的就是data/data/packagename/路径synchronized(mPackages) {if (mSettings.mRenamedPackages.containsKey(pkgName)) {// A package with the same name is already installed, though// it has been renamed to an older name.  The package we// are trying to install should be installed as an update to// the existing one, but that has not been requested, so bail.res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling package running as "+ mSettings.mRenamedPackages.get(pkgName));return;}if (mPackages.containsKey(pkgName)) {                                            //这时候,我们新安装的mPackages中还没有我们的包对应的信息// Don't allow installation over an existing package with the same name.res.setError(INSTALL_FAILED_ALREADY_EXISTS, "Attempt to re-install " + pkgName+ " without first uninstalling.");return;}}try {PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,System.currentTimeMillis(), user);                                     //在这里将我们的包添加到mPackage中,查看Step 28updateSettingsLI(newPackage, installerPackageName, null, null, res);           //这里是更新文件的操作,参考Step 33// delete the partially installed application. the data directory will have to be// restored if it was already existingif (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {// remove package from internal structures.  Note that we want deletePackageX to// delete the package data and cache directories that it created in// scanPackageLocked, unless those directories existed before we even tried to// install.deletePackageLI(pkgName, UserHandle.ALL, false, null, null,dataDirExists ? PackageManager.DELETE_KEEP_DATA : 0,res.removedInfo, true);}} catch (PackageManagerException e) {res.setError("Package couldn't be installed in " + pkg.codePath, e);}}

Step 28 : PackageManagerService.java
    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,long currentTime, UserHandle user) throws PackageManagerException {if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);parseFlags |= mDefParseFlags;PackageParser pp = new PackageParser();pp.setSeparateProcesses(mSeparateProcesses);pp.setOnlyCoreApps(mOnlyCore);pp.setDisplayMetrics(mMetrics);if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;}final PackageParser.Package pkg;try {pkg = pp.parsePackage(scanFile, parseFlags);                    //这里已经是第五次解析了。流程都是一样的} catch (PackageParserException e) {throw PackageManagerException.from(e);}PackageSetting ps = null;PackageSetting updatedPkg;.....                                                              //这里都是一些判断和升级的操作,防止太凌乱,我们关注新安装这部分。// Set application objects path explicitly.pkg.applicationInfo.setCodePath(pkg.codePath);pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);pkg.applicationInfo.setResourcePath(resourcePath);pkg.applicationInfo.setBaseResourcePath(baseResourcePath);pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);// Note that we invoke the following method only if we are about to unpack an applicationPackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags| SCAN_UPDATE_SIGNATURE, currentTime, user);              //进入Step 29中/** If the system app should be overridden by a previously installed* data, hide the system app now and let the /data/app scan pick it up* again.*/if (shouldHideSystemApp) {synchronized (mPackages) {/** We have to grant systems permissions before we hide, because* grantPermissions will assume the package update is trying to* expand its permissions.*/grantPermissionsLPw(pkg, true, pkg.packageName);mSettings.disableSystemPackageLPw(pkg.packageName);}}return scannedPkg;}
Step 29 : PackageManagerService.java
    private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {boolean success = false;try {final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,currentTime, user);success = true;return res;} finally {if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {removeDataDirsLI(pkg.packageName);}}}
Step 30 :PackageManagerService.java

    private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {final File scanFile = new File(pkg.codePath);......// Just create the setting, don't add it yet. For already existing packages// the PkgSetting exists already and doesn't have to be created.pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,pkg.applicationInfo.primaryCpuAbi,pkg.applicationInfo.secondaryCpuAbi,pkg.applicationInfo.flags, user, false);                这个方法比较大,先看我们关注的,进入到Step 31:......return pkg;}
Step 31 :Settings.java
    PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,int pkgFlags, UserHandle user, boolean add) {final String name = pkg.packageName;PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,pkg.mVersionCode, pkgFlags, user, add, true /* allowInstall */);return p;}

Step 32 :Settings.java

    private PackageSetting getPackageLPw(String name, PackageSetting origPackage,String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,String legacyNativeLibraryPathString, String primaryCpuAbiString, String secondaryCpuAbiString,int vc, int pkgFlags, UserHandle installUser, boolean add,boolean allowInstall) {PackageSetting p = mPackages.get(name);UserManagerService userManager = UserManagerService.getInstance();......if (p == null) {if (origPackage != null) {......} else {p = new PackageSetting(name, realName, codePath, resourcePath,legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,null /* cpuAbiOverrideString */, vc, pkgFlags);p.setTimeStamp(codePath.lastModified());p.sharedUser = sharedUser;......if (add) {              //这个在Step 30中可以看到是true// Finish adding new package by adding it and updating shared// user preferencesaddPackageSettingLPw(p, name, sharedUser);}} else {}return p;}
    private void addPackageSettingLPw(PackageSetting p, String name,SharedUserSetting sharedUser) {mPackages.put(name, p);                             //这里将我们的内容加到mPackages中,if (sharedUser != null) {if (p.sharedUser != null && p.sharedUser != sharedUser) {PackageManagerService.reportSettingsProblem(Log.ERROR,"Package " + p.name + " was user "+ p.sharedUser + " but is now " + sharedUser+ "; I am not changing its files so it will probably fail!");p.sharedUser.removePackage(p);} else if (p.appId != sharedUser.userId) {PackageManagerService.reportSettingsProblem(Log.ERROR,"Package " + p.name + " was user id " + p.appId+ " but is now user " + sharedUser+ " with id " + sharedUser.userId+ "; I am not changing its files so it will probably fail!");}sharedUser.addPackage(p);p.sharedUser = sharedUser;p.appId = sharedUser.userId;}}
Step 33 :PackageManagerService.java
    private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,int[] allUsers, boolean[] perUserInstalled,PackageInstalledInfo res) {String pkgName = newPackage.packageName;synchronized (mPackages) {//write settings. the installStatus will be incomplete at this stage.//note that the new package setting would have already been//added to mPackages. It hasn't been persisted yet.mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);                                        //这里更新当前包名对应的安装状态,mSettings.writeLPr();                                                                                                  //这里是写文件的操作,流程比较清晰,就是先备份/data/system/package.xml然后再讲(查看Step 32)写入到里面}if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);synchronized (mPackages) {updatePermissionsLPw(newPackage.packageName, newPackage,UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0? UPDATE_PERMISSIONS_ALL : 0));// For system-bundled packages, we assume that installing an upgraded version// of the package implies that the user actually wants to run that new code,// so we enable the package.if (isSystemApp(newPackage)) {// NB: implicit assumption that system package upgrades apply to all usersif (DEBUG_INSTALL) {Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);}PackageSetting ps = mSettings.mPackages.get(pkgName);if (ps != null) {if (res.origUsers != null) {for (int userHandle : res.origUsers) {ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,userHandle, installerPackageName);}}// Also convey the prior install/uninstall stateif (allUsers != null && perUserInstalled != null) {for (int i = 0; i < allUsers.length; i++) {if (DEBUG_INSTALL) {Slog.d(TAG, "    user " + allUsers[i]+ " => " + perUserInstalled[i]);}ps.setInstalled(perUserInstalled[i], allUsers[i]);}// these install state changes will be persisted in the// upcoming call to mSettings.writeLPr().}}}res.name = pkgName;res.uid = newPackage.applicationInfo.uid;res.pkg = newPackage;mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);mSettings.setInstallerPackageName(pkgName, installerPackageName);res.returnCode = PackageManager.INSTALL_SUCCEEDED;//to update install statusmSettings.writeLPr();                                                            //这里还是更新xml这里的状态就改成安装完成了}}

到这里就结束了,整个应用安装流程。

下面来总结一下都做了什么
1.apk移动到了指定路径/data/app/package-n.apk
2.将apk信息记录在xml中/data/system/packages.xml
3.将apk的信息存到了mPackages中,每次查询apk信息,可以直接到这里来查
 
下面我们随便找一个case来验证一下我们的结论吧,加入我们想要查找apk的应用信息
    @Overridepublic ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {if (!sUserManager.exists(userId)) return null;enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get application info");// writersynchronized (mPackages) {PackageParser.Package p = mPackages.get(packageName);              //这个mPacakges是我们记录下来的。if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getApplicationInfo " + packageName+ ": " + p);if (p != null) {PackageSetting ps = mSettings.mPackages.get(packageName);      //ps使我们存下来的信息if (ps == null) return null;// Note: isEnabledLP() does not apply here - always return inforeturn PackageParser.generateApplicationInfo(p, flags, ps.readUserState(userId), userId);           //我们可以根据这个信息来获取应用信息,}if ("android".equals(packageName)||"system".equals(packageName)) {return mAndroidApplication;}if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);}}return null;}


End

这篇关于android 应用程序安装源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/992881

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、