上一篇讲到如果允许安装未知源程序,并且应用属于未知源程序,就会调用initiateInstall进行安装,而initiateInstall最后会调用startInstallConfirm进行安装确认。这一篇就从startInstallConfirm方法开始讲解。
PackageInstallerActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
private void startInstallConfirm() { // We might need to show permissions, load layout with permissions if (mAppInfo != null) { // 如果程序已经安装过了,那么就显示install_confirm_perm_update界面 bindUi(R.layout.install_confirm_perm_update, true); } else { // 如果程序没有安装,则显示install_confirm_perm界面 bindUi(R.layout.install_confirm_perm, true); } ((TextView) findViewById(R.id.install_confirm_question)) .setText(R.string.install_confirm_question); TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); tabHost.setup(); ViewPager viewPager = (ViewPager)findViewById(R.id.pager); TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager); // Android M开始支持runtime permission,如果是runtime permission的话在这个界面不会显示 boolean supportsRuntimePermissions = mPkgInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; boolean permVisible = false; mScrollView = null; mOkCanInstall = false; int msg = 0; // 这里创建AppSecurityPermissions,该能够将mPkgInfo中的Permission相关信息提出取来 // 并且其内部有一个VIEW类PermissionItemView专门用于展示提出到的权限 AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo); final int N = perms.getPermissionCount(AppSecurityPermissions.WHICH_ALL); // 如果mAppInfo不为null,表示这是升级应用 if (mAppInfo != null) { // 判断是否是system app msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? R.string.install_confirm_question_update_system : R.string.install_confirm_question_update; mScrollView = new CaffeinatedScrollView(this); mScrollView.setFillViewport(true); boolean newPermissionsFound = false; // 根据新添加Permission的情况以及系统版本情况显示不同的提示信息 if (!supportsRuntimePermissions) { newPermissionsFound = (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0); if (newPermissionsFound) { permVisible = true; mScrollView.addView(perms.getPermissionsView( AppSecurityPermissions.WHICH_NEW)); } } if (!supportsRuntimePermissions && !newPermissionsFound) { LayoutInflater inflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE); TextView label = (TextView)inflater.inflate(R.layout.label, null); label.setText(R.string.no_new_perms); mScrollView.addView(label); } // 将升级后的应用所需要的权限显示出来 adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator( getText(R.string.newPerms)), mScrollView); } // 如果不支持运行时权限而且应用所需要的权限个数不为0 if (!supportsRuntimePermissions && N > 0) { permVisible = true; LayoutInflater inflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE); View root = inflater.inflate(R.layout.permissions_list, null); if (mScrollView == null) { mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview); } ((ViewGroup)root.findViewById(R.id.permission_list)).addView( perms.getPermissionsView(AppSecurityPermissions.WHICH_ALL)); // 显示该应用所需要的全部权限 adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator( getText(R.string.allPerms)), root); } if (!permVisible) { if (mAppInfo != null) { // 升级的应用,不需要更多额外的权限 msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? R.string.install_confirm_question_update_system_no_perms : R.string.install_confirm_question_update_no_perms; } else { // 新安装的应用,不需要其他权限 msg = R.string.install_confirm_question_no_perms; } // 加载显示应用不需要权限的界面 bindUi(R.layout.install_confirm, true); mScrollView = null; } if (msg != 0) { ((TextView)findViewById(R.id.install_confirm_question)).setText(msg); } if (mScrollView == null) { // 显示权限的scrollView中没有任何东西时,直接将安装界面的右下角的NEXT按钮修改为install mOk.setText(R.string.install); mOkCanInstall = true; } else { // 否则监听ScrollView事件 mScrollView.setFullScrollAction(new Runnable() { @Override public void run() { mOk.setText(R.string.install); mOkCanInstall = true; } }); } } |
上面安装应用的界面大致如下,升级应用或者应用不需要额外权限的界面大致类似,只是提示信息不同而已:
应用相关信息读取到这里,接下来就到了点击INSTALL确认安装的时候了。
PackageInstallerActivity.onClick
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public void onClick(View v) { if (v == mOk) { if (mOk.isEnabled()) { if (mOkCanInstall || mScrollView == null) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); finish(); } else { // 这里调用startInstall开始安装程序 startInstall(); } } else { // 这里表示此时permission页面显示的是上面左边的图 mScrollView.pageScroll(View.FOCUS_DOWN); } } // Cancel按钮的逻辑 } else if (v == mCancel) { // Cancel and finish setResult(RESULT_CANCELED); if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } finish(); } } |
PackageInstallerActivity.startInstall
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
private void startInstall() { // 跳转到其他Activity进行实际安装过程 Intent newIntent = new Intent(); // 携带PackageInfo信息 newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo); // 传递file协议的Urine newIntent.setData(mPackageURI); newIntent.setClass(this, InstallInstalling.class); 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 != PackageInstaller.SessionParams.UID_UNKNOWN) { 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); finish(); } |
这里并没有立刻开始进行实际的安装动作,而是将相关信息添加到一个Intent中,然后跳转到InstallInstalling这个Activity进行安装,下面我们去阅读这个类的代码来看实际安装所完成的操作。
InstallInstalling.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置正在安装界面 setContentView(R.layout.install_installing); ApplicationInfo appInfo = getIntent() .getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); mPackageURI = getIntent().getData(); if ("package".equals(mPackageURI.getScheme())) { ............. } else { // 打开Uri指定的文件 final File sourceFile = new File(mPackageURI.getPath()); PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo, sourceFile), R.id.app_snippet); // 读取savedInstanceState的信息 if (savedInstanceState != null) { mSessionId = savedInstanceState.getInt(SESSION_ID); mInstallId = savedInstanceState.getInt(INSTALL_ID); // 向InstallEventReceiver注册一个回调 try { InstallEventReceiver.addObserver(this, mInstallId, this::launchFinishBasedOnResult); } catch (EventResultPersister.OutOfIdsException e) { // Does not happen } } else { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER); params.originatingUri = getIntent() .getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); params.originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID, UID_UNKNOWN); File file = new File(mPackageURI.getPath()); try { // 调用parsePackageLite进行轻量级解析 PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0); params.setAppPackageName(pkg.packageName); params.setInstallLocation(pkg.installLocation); params.setSize( PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride)); } catch (PackageParser.PackageParserException e) { Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults."); Log.e(LOG_TAG, "Cannot calculate installed size " + file + ". Try only apk size."); params.setSize(file.length()); } catch (IOException e) { Log.e(LOG_TAG, "Cannot calculate installed size " + file + ". Try only apk size."); params.setSize(file.length()); } try { // 和上面的一样,这里注册一个回调,launchFinishBasedOnResult会接收到安装事件的回调 mInstallId = InstallEventReceiver .addObserver(this, EventResultPersister.GENERATE_NEW_ID, this::launchFinishBasedOnResult); } catch (EventResultPersister.OutOfIdsException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } try { // 生成安装该应用的sessionId mSessionId = getPackageManager().getPackageInstaller().createSession(params); } catch (IOException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } // 监听cancel按钮事件 mCancelButton = (Button) findViewById(R.id.cancel_button); mCancelButton.setOnClickListener(view -> { if (mInstallingTask != null) { mInstallingTask.cancel(true); } if (mSessionId > 0) { getPackageManager().getPackageInstaller().abandonSession(mSessionId); mSessionId = 0; } setResult(RESULT_CANCELED); finish(); }); mSessionCallback = new InstallSessionCallback(); } } |
onCreate只是做一些基本的设置和注册动作,接着我们查看onResume的代码。
onResume
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
protected void onResume() { super.onResume(); // 第一次调用的话,mInstallingTask为null,代表安装应用的task还没有创建 if (mInstallingTask == null) { // 获取PackageInstaller对象 PackageInstaller installer = getPackageManager().getPackageInstaller(); // 根据sessionid获取SessionInfo信息 PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId); // sessionInfo不为null并且不是活动的 if (sessionInfo != null && !sessionInfo.isActive()) { // 创建安装的异步任务 mInstallingTask = new InstallingAsyncTask(); // 调用execute会触发AsyncTask的onPostExecute调用 mInstallingTask.execute(); } else { mCancelButton.setEnabled(false); setFinishOnTouchOutside(false); } } } |
上述SessionInfo代表的是一个安装绘画的详细信息,如果我们安装应用第一次到这里的话,那么这个sessionInfo是处于非活动状态的。接着看InstallingAsyncTask完成什么类型工作。
InstallingAsyncTask
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
private final class InstallingAsyncTask extends AsyncTask<Void, Void, PackageInstaller.Session> { volatile boolean isDone; @Override protected PackageInstaller.Session doInBackground(Void... params) { PackageInstaller.Session session; try { // 根据sessionId创建要给session session = getPackageManager().getPackageInstaller().openSession(mSessionId); } catch (IOException e) { return null; } // 设置安装进度条 session.setStagingProgress(0); try { // 根据Uri打开文件 File file = new File(mPackageURI.getPath()); // 读取文件 try (InputStream in = new FileInputStream(file)) { long sizeBytes = file.length(); // 下面的操作是将文件中的内容写到PackageInstaller的session中 try (OutputStream out = session .openWrite("PackageInstaller", 0, sizeBytes)) { byte[] buffer = new byte[1024 * 1024]; while (true) { int numRead = in.read(buffer); if (numRead == -1) { session.fsync(out); break; } if (isCancelled()) { session.close(); break; } out.write(buffer, 0, numRead); if (sizeBytes > 0) { float fraction = ((float) numRead / (float) sizeBytes); // 设置进度条进度 session.addProgress(fraction); } } } } return session; } catch (IOException | SecurityException e) { Log.e(LOG_TAG, "Could not write package", e); session.close(); return null; } finally { synchronized (this) { isDone = true; notifyAll(); } } } @Override protected void onPostExecute(PackageInstaller.Session session) { if (session != null) { // 创建一个intent,其中的Action为: // BROADCAST_ACTION = "com.android.packageinstaller.ACTION_INSTALL_COMMIT"; Intent broadcastIntent = new Intent(BROADCAST_ACTION); broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntent.setPackage( getPackageManager().getPermissionControllerPackageName()); broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId); // 创建一个pendingIntent PendingIntent pendingIntent = PendingIntent.getBroadcast( InstallInstalling.this, mInstallId, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); // 调用session的commit方法将intent发送出去 session.commit(pendingIntent.getIntentSender()); // 此时将cancel按钮设置为不可用 mCancelButton.setEnabled(false); setFinishOnTouchOutside(false); } else { getPackageManager().getPackageInstaller().abandonSession(mSessionId); if (!isCancelled()) { launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null); } } } } |
接下来分析PackageInstaller.Session的commit方法完成的事情。
commit
1 2 3 4 5 6 7 |
public void commit(@NonNull IntentSender statusReceiver) { try { mSession.commit(statusReceiver, false); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } |
上述mSession定义如下为private IPackageInstallerSession mSession;
,代表mSession是一个IPackageInstallSession代理对象,通过这个代理可以和PackageInstallerSession进行binder通信。
PackageInstallSession.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) { Preconditions.checkNotNull(statusReceiver); final boolean wasSealed; synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); assertPreparedAndNotDestroyedLocked("commit"); // 将安装包的信息 final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter( mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId); mRemoteObserver = adapter.getBinder(); // forTransfer为false if (forTransfer) { mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null); if (mInstallerUid == mOriginalInstallerUid) { throw new IllegalArgumentException("Session has not been transferred"); } } else { if (mInstallerUid != mOriginalInstallerUid) { throw new IllegalArgumentException("Session has been transferred"); } } // 初始化时mSealed为false,在sealAndValidateLocked中会将mSealed置为true wasSealed = mSealed; if (!mSealed) { try { // 封装好session,防止session信息被修改 sealAndValidateLocked(); } catch (IOException e) { throw new IllegalArgumentException(e); } catch (PackageManagerException e) { destroyInternal(); mHandler.obtainMessage(MSG_SESSION_FINISHED_WITH_EXCEPTION, e).sendToTarget(); return; } } mClientProgress = 1f; computeProgressLocked(true); mActiveCount.incrementAndGet(); // 然后想mHandler发送MSG_COMMIT信息 mCommitted = true; mHandler.obtainMessage(MSG_COMMIT).sendToTarget(); } if (!wasSealed) { mCallback.onSessionSealedBlocking(this); } } |
上面的代码最主要的是在最后的部分通过mHandler发送MSG_COMMIT消息。mHandler是Handler对象,其通过mHandler = new Handler(looper, mHandlerCallback);
进行初始化。
mHandlerCallback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_COMMIT: synchronized (mLock) { try { // MSG_COMMIT的主要处理函数 commitLocked(); } catch (PackageManagerException e) { final String completeMsg = ExceptionUtils.getCompleteMessage(e); Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg); destroyInternal(); dispatchSessionFinished(e.error, completeMsg, null); } } break; case MSG_SESSION_FINISHED_WITH_EXCEPTION: ................ break; } return true; } }; |
上面的代码处理起来比较简单,主要调用commitLocked来完成。下面直接来看commitLocked方法的代码。
commitLocked
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
private void commitLocked() throws PackageManagerException { if (mDestroyed) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed"); } if (!mSealed) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed"); } // 检查所需参数 Preconditions.checkNotNull(mPackageName); Preconditions.checkNotNull(mSignatures); Preconditions.checkNotNull(mResolvedBaseFile); // 检擦是否仍有权限需要确认 if (needToAskForPermissionsLocked()) { // User needs to accept permissions; give installer an intent they // can use to involve user. final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_PERMISSIONS); intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName()); intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); try { mRemoteObserver.onUserActionRequired(intent); } catch (RemoteException ignored) { } // Commit was keeping session marked as active until now; release // that extra refcount so session appears idle. closeInternal(false); return; } if (stageCid != null) { // Figure out the final installed size and resize the container once // and for all. Internally the parser handles straddling between two // locations when inheriting. final long finalSize = calculateInstalledSize(); resizeContainer(stageCid, finalSize); } // 继承现有安装包中没有被覆盖的native库 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) { try { final List<File> fromFiles = mResolvedInheritedFiles; final File toDir = resolveStageDirLocked(); if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles); if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) { throw new IllegalStateException("mInheritedFilesBase == null"); } if (isLinkPossible(fromFiles, toDir)) { if (!mResolvedInstructionSets.isEmpty()) { final File oatDir = new File(toDir, "oat"); createOatDirs(mResolvedInstructionSets, oatDir); } linkFiles(fromFiles, toDir, mInheritedFilesBase); } else { // TODO: this should delegate to DCS so the system process // avoids holding open FDs into containers. copyFiles(fromFiles, toDir); } } catch (IOException e) { throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed to inherit existing install", e); } } mInternalProgress = 0.5f; computeProgressLocked(true); // 解压native库 extractNativeLibraries(mResolvedStageDir, params.abiOverride); if (stageCid != null) { finalizeAndFixContainer(stageCid); } // 获取IPackageInstallObserver2对象,用于binder通信 final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() { @Override public void onUserActionRequired(Intent intent) { throw new IllegalStateException(); } @Override public void onPackageInstalled(String basePackageName, int returnCode, String msg, Bundle extras) { destroyInternal(); dispatchSessionFinished(returnCode, msg, extras); } }; final UserHandle user; if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) { user = UserHandle.ALL; } else { user = new UserHandle(userId); } // 最最最重要的部分了,这里会调用PackageManager进行最后的安装动作 mRelinquished = true; mPm.installStage(mPackageName, stageDir, stageCid, localObserver, params, mInstallerPackageName, mInstallerUid, user, mCertificates); } |
上面的代码到最后PackageInstallerSession的使命就到此结束了,最后会跳转到PackageManagerServic中执行。这一篇就先到这里了,之后PackageManagerServic的处理到下一篇再讲述。
小结
下面是这篇文章的简单总结:
- 在startInstallConfirm中会显示安装包内定义所需的权限信息
- 在点击Install后APK的内容会通过IO流的方式写到PackageInsaller.Session中
- 最后会调用PackageInstaller.Session的commit方法将请求到PKMS中
最后在PKMS中的处理我们留待下一篇再分析。