本文主要是介绍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();}
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的地方}}
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来依次执行操作。}
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
Step 12 : PackageManagerService$PackageHandlerprivate InstallArgs createInstallArgs(InstallParams params) {if (installOnSd(params.installFlags) || params.isForwardLocked()) {return new AsecInstallArgs(params);} else {return new FileInstallArgs(params);}}
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.javapublic 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.javaStep 15 : 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;}}
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.javapublic static PackageLite parsePackageLite(File packageFile, int flags)throws PackageParserException {if (packageFile.isDirectory()) { //这里会看是否是路径,我们解析apk的时候,传的都是文件。return parseClusterPackageLite(packageFile, flags);} else {return parseMonolithicPackageLite(packageFile, flags);}}
Step 17 : PackageParser.javaprivate 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信息实例,这里就相当于比轻量级略多信息的实例了,}
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.javaStep 19 : android_util_AssetManager.cpppublic 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);}
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.javaprivate 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到这里我们已经对整个apk的拷贝过程基本了解里,下面我们在回到Step 9中,看看拷贝之后做了哪些事情。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;}}
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.javaprivate 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.javaprivate 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$FileInstallArgsStep 26 : PackageManagerService.java$FileInstallArgsboolean 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 27 : PackageManagerService.javaprivate File getNextCodePath(String packageName) {int suffix = 1;File result;do {result = new File(mAppInstallDir, packageName + "-" + suffix);suffix++;} while (result.exists());return result;}
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.javaStep 29 : PackageManagerService.javaprivate 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 30 :PackageManagerService.javaprivate 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 31 :Settings.javaprivate 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;}
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.javaprivate 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;}
Step 33 :PackageManagerService.javaprivate 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;}}
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 应用程序安装源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!