編輯:關於Android編程
這篇文章,來學習apk的安裝流程,在開始之前,先看看我們在APP中是通過下面代碼來安裝apk的
Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive"); context.startActivity(intent);
構造一個intent,並且setDataAndType,然後啟動這個activity,此時系統默認的安裝apk的PackageInstallerActivity界面就出現了。
在PackageInstallerActivity中定義了這樣的字符串
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
這個是在PackageManagerService中匹配的。
PackageInstallerActivity也是一個activity,所以當該界面顯示的時候,會首先調用其onCreate方法,我們來看看。
@Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mPm = getPackageManager(); //是一個PackageManager實例,具體用來執行安裝操作的 mInstaller = mPm.getPackageInstaller(); // PackageInstaller實例,在該實例中包含了安裝apk的基本信息 mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); final Intent intent = getIntent(); //set view setContentView(R.layout.install_start); mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); // Block the install attempt on the Unknown Sources setting if necessary. if (!requestFromUnknownSource) { // 為安裝操作,執行一些初始化的工作 initiateInstall(); return; } }
可以看到,在onCreate中,主要通過initiateInstall();為安裝操作,執行一些初始化的工作。
private void initiateInstall() { // 當前apk的包名 String pkgName = mPkgInfo.packageName; // Check if there is already a package on the device with this name // but it has been renamed to something else. String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName }); if (oldName != null && oldName.length > 0 && oldName[0] != null) { pkgName = oldName[0]; mPkgInfo.packageName = pkgName; mPkgInfo.applicationInfo.packageName = pkgName; } try { // 通過PackageManager從系統中獲取沒有安裝的apk的信息 mAppInfo = mPm.getApplicationInfo(pkgName, PackageManager.GET_UNINSTALLED_PACKAGES); // 如果已經安裝,在後面會給出用戶是否替換的提示 if ((mAppInfo.flags& ApplicationInfo.FLAG_INSTALLED) == 0) { mAppInfo = null; } } catch (PackageManager.NameNotFoundException e) { mAppInfo = null; } // 調用startInstallConfirm進行進一步的安裝操作 startInstallConfirm(); }
上面代碼最終主要該通過startInstallConfirm來進一步安裝apk
private void startInstallConfirm() { mInstallConfirm.setVisibility(View.VISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); } PackageInstallerActivity實現了OnClicklistener public void onClick(View v) { if (v == mOk) { startInstall(); } else if(v == mCancel) { // Cancel and finish setResult(RESULT_CANCELED); finish(); } } private void startInstall() { // 安裝apk,構造intent,這裡會跳轉到InstallAppProgress裡 Intent newIntent = new Intent(); // 傳遞數據 newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo); newIntent.setData(mPackageURI); 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); } // 進入InstallAppProgress startActivity(newIntent); finish(); }
可以看到在startInstall方法中,主要構造一個intent,並且傳遞必要的數據,跳轉到InstallAppProgress類,在該類中有一個initView方法
public void initView() { setContentView(R.layout.op_progress); int installFlags = 0; PackageManager pm = getPackageManager(); // 判斷當前apk是否已經安裝過 try { PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES); if(pi != null) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; } } catch (PackageManager.NameNotFoundException e) { } // 省略代碼 // 構造一個PackageInstallObserver,當安裝完成以後,回調對應的方法 PackageInstallObserver observer = new PackageInstallObserver(); if ("package".equals(mPackageURI.getScheme())) { try { // 調用PackageManagerService服務的installExistingPackage進行安裝 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); } }
這裡具體的PackageManagerService服務安裝的過程我們稍後會進行學習,先看下當安裝完成以後通過PackageInstallObserver執行的回調方法
class PackageInstallObserver extends IPackageInstallObserver.Stub { public void packageInstalled(String packageName, int returnCode) { Message msg = mHandler.obtainMessage(INSTALL_COMPLETE); msg.arg1 = returnCode; mHandler.sendMessage(msg); } }
發送”INSTALL_COMPLETE”這樣的消息到自身,在handleMessage中主要做了下面的操作:
mLaunchIntent = getPackageManager().getLaunchIntentForPackage( mAppInfo.packageName); mLaunchButton.setOnClickListener(InstallAppProgress.this); mDoneButton.setOnClickListener(InstallAppProgress.this);
獲取啟動當前apk的intent,並且為done和lunch按鈕設置點擊事件
public void onClick(View v) { if(v == mDoneButton) { if (mAppInfo.packageName != null) { Log.i(TAG, "Finished installing "+mAppInfo.packageName); } finish(); } else if(v == mLaunchButton) { startActivity(mLaunchIntent); finish(); } }
好了,到現在為止,使用PackageInstallerActivity安裝apk的整個流程已經梳理完畢,實際上真正執行安裝操作的都是交給了PackageManagerService服務的installExistingPackage進行安裝的
平時我們可以使用下面兩個命令來安裝apk
pm get-install-location 查找安裝apk的位置 一般默認 為0[auto] pm set-install-location 設置位置
這裡最終都是通過PackageManagerService來實現安裝具體包的操作
調用PackageManagerService#installPackage方法開始apk的安裝過程
public void installPackage(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride) { installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams, packageAbiOverride, UserHandle.getCallingUserId()); } @Override public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride, int userId) { // 檢查是否有install權限 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); final int callingUid = Binder.getCallingUid(); enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser"); // 判斷當前用戶是否被Restricted,回調onPackageInstalled方法,安裝失敗 if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) { try { if (observer != null) { observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null); } } catch (RemoteException re) { } return; } // 代碼省略,主要是判斷當前安裝的方式設置對應的installFlags final File originFile = new File(originPath); final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile); // 發送"INIT_COPY" 消息,構造InstallParams參數 final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName, null, verificationParams, user, packageAbiOverride, null); mHandler.sendMessage(msg); }
整個PackageHandler是PackageManagerService的一個內部類
witch (msg.what) { case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; //這裡獲取當前需要安裝的apk個數,mPendingInstalls保存著所有需要安裝的apk解析出來的HandlerParams參數 int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); // 如果沒有綁定DefaultContainerService,則進行那個綁定,DefaultContainerService主要負責計算當前存儲和拷貝工作 if (!mBound) { if (!connectToService()) { params.serviceError(); return; } else { mPendingInstalls.add(idx, params); } } else { mPendingInstalls.add(idx, params); if (idx == 0) { mHandler.sendEmptyMessage(MCS_BOUND); } } break; }
繼續發送”MCS_BOUND”參數到自己處理,表示綁定DefaultContainerService服務完成
case MCS_BOUND: { if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; } if (mContainerService == null) { // 綁定DefaultContainerService服務失敗,回調serviceError方法 if (!mBound) { Slog.e(TAG, "Cannot bind to media container service"); for (HandlerParams params : mPendingInstalls) { params.serviceError(); } mPendingInstalls.clear(); } else { Slog.w(TAG, "Waiting to connect to media container service"); } } else if (mPendingInstalls.size() > 0) { // 總是安裝隊列中的第一個 HandlerParams params = mPendingInstalls.get(0); if (params != null) { if (params.startCopy()) { //首先拷貝當前apk到對應的目錄下 // We are done... look for more work or to // go idle. if (mPendingInstalls.size() > 0) { // 將第一個移除當前隊列 mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { //size等於0,表示所有的apk都已經安裝完成,unbind當前DefaultContainerService服務 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 { //繼續安裝下一個需要安裝的包 mHandler.sendEmptyMessage(MCS_BOUND); } } } } else { Slog.w(TAG, "Empty queue"); } break; }
可以看到,其實所有的安裝apk的代碼都放到了HandlerParams#startCopy方法中,看下HandlerParams
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 { // 這裡的具體copy處理是由其子類來完成的 handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } // handleReturnCode,該方法會在handleStartCopy執行玩拷貝相關動作之後,根據在handleStartCopy中的做進一步處理 handleReturnCode(); return res; } final void serviceError() { if (DEBUG_INSTALL) Slog.i(TAG, "serviceError"); handleServiceError(); handleReturnCode(); } abstract void handleStartCopy() throws RemoteException; abstract void handleServiceError(); abstract void handleReturnCode(); } }
這裡是由InstallParams來處理copy操作的。
public void handleStartCopy() throws RemoteException { int ret = PackageManager.INSTALL_SUCCEEDED; if (origin.staged) { if (origin.file != null) { installFlags |= PackageManager.INSTALL_INTERNAL; installFlags &= ~PackageManager.INSTALL_EXTERNAL; } else if (origin.cid != null) { installFlags |= PackageManager.INSTALL_EXTERNAL; installFlags &= ~PackageManager.INSTALL_INTERNAL; } else { throw new IllegalStateException("Invalid stage location"); } } // 是否安裝到sdcard或者內部存儲中 final boolean onSd = (installFlags & PackageManager.INSTALL_EXTERNAL) != 0; final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0; PackageInfoLite pkgLite = null; if (onInt && onSd) { // 用戶同時設置安裝到sdcard和內部存儲 Slog.w(TAG, "Conflicting flags specified for installing on both internal and external"); ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; } else { pkgLite = mContainerService.getMinimalPackageInfo(origin.resolvedPath, installFlags, packageAbiOverride); ....... //代碼省略,主要根據存儲情況,釋放當前存儲空間 } // 根據當前InstallParams構造具體的InstallArgs實現類,在該實現類中做具體的拷貝操作 final InstallArgs args = createInstallArgs(this); mArgs = args; if (ret == PackageManager.INSTALL_SUCCEEDED) { /* * ADB installs appear as UserHandle.USER_ALL, and can only be performed by * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER. */ int userIdentifier = getUser().getIdentifier(); if (userIdentifier == UserHandle.USER_ALL && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) { userIdentifier = UserHandle.USER_OWNER; } final int requiredUid = mRequiredVerifierPackage == null ? -1 : getPackageUid(mRequiredVerifierPackage, userIdentifier); if (!origin.existing && requiredUid != -1 && isVerificationEnabled(userIdentifier, installFlags) && isVerificationRequired()) { // 對當前的包做驗證操作 final Intent verification = new Intent( Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); verification.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)), PACKAGE_MIME_TYPE); verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); final Listreceivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */); final int verificationId = mPendingVerificationToken++; verification.putExtra(PackageManager.EXTRA_VERIFICATION_ID, verificationId); verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE, installerPackageName); verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, installFlags); verification.putExtra(PackageManager.EXTRA_VERIFICATION_PACKAGE_NAME, pkgLite.packageName); verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE, pkgLite.versionCode); if (verificationParams != null) { if (verificationParams.getVerificationURI() != null) { verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI, verificationParams.getVerificationURI()); } if (verificationParams.getOriginatingURI() != null) { verification.putExtra(Intent.EXTRA_ORIGINATING_URI, verificationParams.getOriginatingURI()); } if (verificationParams.getReferrer() != null) { verification.putExtra(Intent.EXTRA_REFERRER, verificationParams.getReferrer()); } if (verificationParams.getOriginatingUid() >= 0) { verification.putExtra(Intent.EXTRA_ORIGINATING_UID, verificationParams.getOriginatingUid()); } if (verificationParams.getInstallerUid() >= 0) { verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID, verificationParams.getInstallerUid()); } } final PackageVerificationState verificationState = new PackageVerificationState( requiredUid, args); mPendingVerification.append(verificationId, verificationState); final List sufficientVerifiers = matchVerifiers(pkgLite, receivers, verificationState); // Apps installed for "all" users use the device owner to verify the app UserHandle verifierUser = getUser(); if (verifierUser == UserHandle.ALL) { verifierUser = UserHandle.OWNER; } /* * If any sufficient verifiers were listed in the package * manifest, attempt to ask them. */ if (sufficientVerifiers != null) { final int N = sufficientVerifiers.size(); if (N == 0) { Slog.i(TAG, "Additional verifiers required, but none installed."); ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE; } else { for (int i = 0; i < N; i++) { final ComponentName verifierComponent = sufficientVerifiers.get(i); final Intent sufficientIntent = new Intent(verification); sufficientIntent.setComponent(verifierComponent); mContext.sendBroadcastAsUser(sufficientIntent, verifierUser); } } } final ComponentName requiredVerifierComponent = matchComponentForVerifier( mRequiredVerifierPackage, receivers); 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, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final Message msg = mHandler .obtainMessage(CHECK_PENDING_VERIFICATION); msg.arg1 = verificationId; mHandler.sendMessageDelayed(msg, getVerificationTimeout()); } }, null, 0, null, null); /* * We don't want the copy to proceed until verification * succeeds, so null out this field. */ mArgs = null; } } else { // 執行拷貝操作 ret = args.copyApk(mContainerService, true); } } mRet = ret; }
上面主要做了這樣的事情:
1. 判斷安裝默認存儲
2. 若當前存儲不夠,則釋放儲存空間
3. 如果需要,對當前包做驗證操作
4. 執行拷貝操作
就安裝而言,最重要的還是最後的執行拷貝操作,這裡是InstallArgs#copyApk
static abstract class InstallArgs
包含三個子類
1. FileInstallArgs apk安裝到內部存儲器時使用。
2. AsecInstallArgs 安裝到sdcard或者ForwardLocked時使用
3. MoveInstallArgs 移動包的位置,比如從內部存儲移動到sdcard上
在構造方法中根據InstallParams會構造出具體類型
private InstallArgs createInstallArgs(InstallParams params) { if (params.move != null) { return new MoveInstallArgs(params); } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) { return new AsecInstallArgs(params); } else { return new FileInstallArgs(params); } }
這裡我們以AsecInstallArgs為例,進行說明
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException { if (origin.staged) { if (DEBUG_INSTALL) Slog.d(TAG, origin.cid + " already staged; skipping copy"); cid = origin.cid; setMountPath(PackageHelper.getSdDir(cid)); return PackageManager.INSTALL_SUCCEEDED; } if (temp) { createCopyFile(); } else { /* * Pre-emptively destroy the container since it's destroyed if * copying fails due to it existing anyway. */ PackageHelper.destroySdDir(cid); } //copyPackageToContainer執行真正的拷貝操作 final String newMountPath = imcs.copyPackageToContainer( origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(), isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */)); if (newMountPath != null) { setMountPath(newMountPath); return PackageManager.INSTALL_SUCCEEDED; //這裡安裝成功之後,會將mRet賦值為PackageManager.INSTALL_SUCCEEDED } else { return PackageManager.INSTALL_FAILED_CONTAINER_ERROR; } }
到現在為止,copyApk的操作已經完成,接下來交給handleReturnCode處理
@Override void handleReturnCode() { // mArgs是在handleStartCopy中創建的 if (mArgs != null) { processPendingInstall(mArgs, mRet); } } private void processPendingInstall(final InstallArgs args, final int currentStatus) { // 由於安裝可能耗時操作,所以這裡開啟了一個線程 mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); // Result object to be returned PackageInstalledInfo res = new PackageInstalledInfo(); res.returnCode = currentStatus; res.uid = -1; res.pkg = null; res.removedInfo = new PackageRemovedInfo(); // 如果之前copyApk正常執行完成,這裡res.returnCode == PackageManager.INSTALL_SUCCEEDED成立 if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { args.doPreInstall(res.returnCode); //安裝前的准備工作 synchronized (mInstallLock) { installPackageLI(args, res); //執行安裝操作 } args.doPostInstall(res.returnCode, res.uid); //安裝完成以後的曹操作 } ......... Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); // 安裝完成後發送"POST_INSTALL"廣播 mHandler.sendMessage(msg); } }); }
看下進一步安裝的相關步驟
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) { ...... PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setDisplayMetrics(mMetrics); pp.setRuntimeSkinBlacklist(mRuntimeSkinManager.getBlacklistedPackages()); final PackageParser.Package pkg; try { // PackageParser解析manifest文件 pkg = pp.parsePackage(tmpPackageFile, parseFlags); } catch (PackageParser.PackageParserException e) { res.setError("Failed parse during installPackageLI", e); return; } // Mark that we have an install time CPU ABI override. pkg.cpuAbiOverride = args.abiOverride; String pkgName = res.name = pkg.packageName; // Mark that we have an install time CPU ABI override. pkg.cpuAbiOverride = args.abiOverride; String pkgName = res.name = pkg.packageName; // 根據用戶策略,判斷當前用戶是否允許安裝apk,否則直接返回 boolean installForAllUsers = ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0); int user = args.user == null ? -1 : args.user.getIdentifier(); if (isInstallationBlockedByDevicePolicy(pkgName, installForAllUsers, user)) { res.returnCode = PackageManager.INSTALL_FAILED_USER_RESTRICTED; return; } // 簽名相關信息 try { pp.collectCertificates(pkg, parseFlags); pp.collectManifestDigest(pkg); } catch (PackageParser.PackageParserException e) { res.setError("Failed collect during installPackageLI", e); return; } ........ // 如果已經安裝當前應用,則替換,否則安裝 if (replace) { replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user, installerPackageName, volumeUuid, res); } else { installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES, args.user, installerPackageName, volumeUuid, res); } }
可以看到上面的代碼主要做了下面操作:
1. 解析manifest文件,並且將解析結果封裝成PackageParser對象
2. 判斷當前安裝條件四是否滿足,否則直接返回,比如:根據用戶策略,判斷當前用戶是否允許安裝apk,否則直接返回
3. 獲取簽名相關信息,並且做校驗
4. 安裝或者替換當前應用installNewPackageLI或者replacePackageLI
PackageParser解析manifest文件,PackageParser#parsePackage —-> PackageParser#parseClusterPackage —> PackageParser#parseBaseApk
private Package parseBaseApk(File apkFile, AssetManager assets, int flags) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); String volumeUuid = null; if (apkPath.startsWith(MNT_EXPAND)) { final int end = apkPath.indexOf('/', MNT_EXPAND.length()); volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); } mParseError = PackageManager.INSTALL_SUCCEEDED; mArchiveSourcePath = apkFile.getAbsolutePath(); if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); Resources res = null; XmlResourceParser parser = null; try { res = new Resources(assets, mMetrics, null); assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); // 解析manifest文件 parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); final String[] outError = new String[1]; final Package pkg = parseBaseApk(res, parser, flags, outError); if (pkg == null) { throw new PackageParserException(mParseError, apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); } pkg.volumeUuid = volumeUuid; pkg.applicationInfo.volumeUuid = volumeUuid; pkg.baseCodePath = apkPath; pkg.mSignatures = null; return pkg; } catch (PackageParserException e) { throw e; } catch (Exception e) { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, "Failed to read manifest from " + apkPath, e); } finally { IoUtils.closeQuietly(parser); } }
通過installNewPackageLI執行安裝操作
/* * Install a non-existing package. */ private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user, String installerPackageName, String volumeUuid, PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; ....... try { // 核心的調用 PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags, System.currentTimeMillis(), user); updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user); //如果安裝失敗,則執行回退操作,刪除創建的文件夾等緩存文件 if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) { 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); } } 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; // 程序走到這裡說明安裝成功了,這裡會返回根據解析構建的Package對象,該對象中包含了該apk對應的manifest中的信息 return res; } finally { if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) { removeDataDirsLI(pkg.volumeUuid, pkg.packageName); } } }
**終於走到了scanPackageDirtyLI方法,安裝apk的核心方法:
在該方法中,會根據之前解析出來的內容,添加到對應的list中,方便以後query查詢**
// Currently known shared libraries. final ArrayMapmSharedLibraries = new ArrayMap (); // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = new ActivityIntentResolver(); // All available receivers, for your resolving pleasure. final ActivityIntentResolver mReceivers = new ActivityIntentResolver(); // All available services, for your resolving pleasure. final ServiceIntentResolver mServices = new ServiceIntentResolver(); // All available providers, for your resolving pleasure. final ProviderIntentResolver mProviders = new ProviderIntentResolver(); private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { ....... int N = pkg.providers.size(); StringBuilder r = null; int i; for (i=0; i
好了,關於apk的安裝的大致流程就到這裡了。下面畫一張圖來總結一下,如有遺漏或者不對的地方,歡迎指教。
1.簡介 對於android中的ListView刷新機制,大多數的程序員都是很熟悉的,修改或者添加adapter中的數據源之後,然後調用notifyDataSetChan
一、什麼是鎖在Java的util.concurrent.locks包下有關於鎖的接口和類如下:先看一段代碼:package com.codeing.snail.test;
定義外觀模式(Facade Pattern):外部與一個子系統的通信必須通過一個統一的外觀對象進行,為子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這
前言新版本ShareSDK的分享和短信驗證,按官網的文檔,都需要添加一個標簽,而分享和短息驗證的這個標簽內容都一樣。會沖突。解決辦法:分享用舊版本,短信驗證用新版本。後面