Android12分析(更新内容、Android apk安装、适配)

您所在的位置:网站首页 scheme协议 Android12分析(更新内容、Android apk安装、适配)

Android12分析(更新内容、Android apk安装、适配)

2023-10-07 08:49| 来源: 网络整理| 查看: 265

Android 12 新功能分析 developer.android.com/about/versi… blog.csdn.net/weixin_4061… 关于存储: /** * Allow apps to create the requests to manage the media files without user confirmation. * * @see android.Manifest.permission#MANAGE_MEDIA * @see android.provider.MediaStore#createDeleteRequest(ContentResolver, Collection) * @see android.provider.MediaStore#createTrashRequest(ContentResolver, Collection, boolean) * @see android.provider.MediaStore#createWriteRequest(ContentResolver, Collection) * * @hide */

juejin.cn/post/693236…

关于项目中的适配 android 12 适配 (kdocs.cn)

apk的大体流程如下:

· 第一步:拷贝文件到指定的目录: 在Android系统中,apk安装文件是会被保存起来的,默认情况下,用户安装的apk首先会被拷贝到/data/app目录下,/data/app目录是用户有权限访问的目录,在安装apk的时候会自动选择该目录存放用户安装的文件,而系统出场的apk文件则被放到了/system分区下,包括/system/app,/system/vendor/app,以及/system/priv-app等等,该分区只有ROOT权限的用户才能访问,这也就是为什么在没有Root手机之前,我们没法删除系统出场的app的原因了。

· 第二步:解压缩apk,宝贝文件,创建应用的数据目录 为了加快app的启动速度,apk在安装的时候,会首先将app的可执行文件dex拷贝到/data/dalvik-cache目录,缓存起来。然后,在/data/data/目录下创建应用程序的数据目录(以应用的包名命名),存放在应用的相关数据,如数据库、xml文件、cache、二进制的so动态库等。

· 第三步:解析apk的AndroidManifest.xml文件

Android系统中,也有一个类似注册表的东西,用来记录当前所有安装的应用的基本信息,每次系统安装或者卸载了任何apk文件,都会更新这个文件。这个文件位于如下目录:/data/system/packages.xml。系统在安装这个apk的过程中,会解析apk的AndroidManifest.xml文件,提取出这个apk的重要信息写入到packages.xml文件中,这些信息包括:权限、应用包名、APK的安装位置、版本、userID等等。由此,我们就知道了为什么一些应用市场和软件管理类的app能够很清楚地知道当前手机所安装的所有app,以及这些app的详细信息了。另外一件事就是Linux的用户Id和用户组Id,以便他们可以获得合适的运行权限。以上都是由PackageServcieManager完成的,后面我们会重点介绍PackageServiceManager。

第四步:显示快捷方式 如果这些应用程序在PackageManagerService服务注册好了,如果我们想要在Android桌米上看到这些应用程序,还需要有一个Home应用程序,负责从PackageManagerService服务中把这些安装好的应用程序取出来,并以友好的方式在桌面上展现出来,例如以快捷图标的形式。在Android系统中,负责把系统中已经安装的应用程序在桌面中展现出来的Home应用就是Launcher了。 安装 APK 主要分为以下三种场景

安装系统应用:系统启动后调用 PackageManagerService.main() 初始化注册解析安装工作 public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { // Self-check for initial settings. PackageManagerServiceCompilerMapping.checkProperties(); PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); m.enableSystemUserPackages(); ServiceManager.addService("package", m); final PackageManagerNative pmn = m.new PackageManagerNative(); ServiceManager.addService("package_native", pmn); return m; } 通过 adb 安装:通过 pm 参数,调用 PM 的 runInstall 方法,进入 PackageManagerService 安装安装工作 通过系统安装器 PackageInstaller 进行安装:先调用 InstallStart 进行权限检查之后启动 PackageInstallActivity,调用 PackageInstallActivity 的 startInstall 方法,点击 OK 按钮后进入 PackageManagerService 完成拷贝解析安装工作

所有安装方式大致相同,最终就是回到 PackageManagerService 中,安装一个 APK 的大致流程如下:

拷贝到 APK 文件到指定目录 解压缩 APK,拷贝文件,创建应用的数据目录 解析 APK 的 AndroidManifest.xml 文件 向 Launcher 应用申请添加创建快捷方式

本文主要来分析通过安装器 PackageInstaller 安装 APK,这是用户最常用的一种方式

7.0以前安装的入口是PackageInstallerActivity 7.0以后是InstallStart

3.1 InstallStart

主要工作:

判断是否勾选“未知来源”选项,若未勾选跳转到设置安装未知来源界面 对于大于等于 Android 8.0 版本,会先检查是否申请安装权限,若没有则中断安装 判断 Uri 的 Scheme 协议,若是 content 则调用 InstallStaging, 若是 package 则调用 PackageInstallerActivity,但是实际上 installStaging中的 StagingAsyncTask 会将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity,所以最终安装的开始还是PackageInstallerActivity

3.2 PackageInstallerActivity

主要工作:

显示安装界面 初始化安装需要用的各种对象,比如 PackageManager、IPackageManager、AppOpsManager、UserManager、PackageInstaller 等等 根据传递过来的 Scheme 协议做不同的处理 检查是否允许、初始化安装 在准备安装的之前,检查应用列表判断该应用是否已安装,若已安装则提示该应用已安装,由用户决定是否替换 在安装界面,提取出 APK 中权限信息并展示出来 点击 OK 按钮确认安装后,会调用 startInstall 开始安装工作 protected void onCreate(Bundle icicle) { getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); super.onCreate(null); // 初始化安装需要用到的对象 mPm = getPackageManager(); mIpm = AppGlobals.getPackageManager(); mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE); mInstaller = mPm.getPackageInstaller(); mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); // 根据Uri的Scheme做不同的处理 boolean wasSetUp = processPackageUri(packageUri); if (!wasSetUp) { return; } // 显示安装界面 bindUi(); // 检查是否允许安装包,如果允许则启动安装。如果不允许显示适当的对话框 checkIfAllowedAndInitiateInstall(); }

主要做了对象的初始化,解析 Uri 的 Scheme,初始化界面,安装包检查等等工作,接着查看一下

processPackageUri 方法

private boolean processPackageUri(final Uri packageUri) { mPackageURI = packageUri; final String scheme = packageUri.getScheme(); // 根据这个Scheme协议分别对package协议和file协议进行处理 switch (scheme) { case SCHEME_PACKAGE: { try { // 通过PackageManager对象获取指定包名的包信息 mPkgInfo = mPm.getPackageInfo(packageUri.getSchemeSpecificPart(), PackageManager.GET_PERMISSIONS | PackageManager.MATCH_UNINSTALLED_PACKAGES); } catch (NameNotFoundException e) { } if (mPkgInfo == null) { Log.w(TAG, "Requested package " + packageUri.getScheme() + " not available. Discontinuing installation"); showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); return false; } mAppSnippet = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), mPm.getApplicationIcon(mPkgInfo.applicationInfo)); } break; case ContentResolver.SCHEME_FILE: { // 根据packageUri创建一个新的File File sourceFile = new File(packageUri.getPath()); // 解析APK得到APK的信息,PackageParser.Package存储了APK的所有信息 PackageParser.Package parsed = PackageUtil.getPackageInfo(this, sourceFile); if (parsed == null) { Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); return false; } // 根据PackageParser.Package得到的APK信息,生成PackageInfo mPkgInfo = PackageParser.generatePackageInfo(parsed, null, PackageManager.GET_PERMISSIONS, 0, 0, null, new PackageUserState()); mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); } break; default: { throw new IllegalArgumentException("Unexpected URI scheme " + packageUri); } } return true; }

主要对 Scheme 协议分别对 package 协议和 file 协议进行处理 SCHEME_PACKAGE:

在 package 协议中调用了 PackageManager.getPackageInfo 方法生成 PackageInfo,PackageInfo 是跨进程传递的包数据(activities、receivers、services、providers、permissions等等)包含 APK 的所有信息

SCHEME_FILE:

在 file 协议的处理中调用了 PackageUtil.getPackageInfo 方法,方法内部调用了 PackageParser.parsePackage() 把 APK 文件的 manifest 和签名信息都解析完成并保存在了 Package,Package 包含了该 APK 的所有信息 调用 PackageParser.generatePackageInfo 生成 PackageInfo

接着往下走,都解析完成之后,回到 onCreate 方法,继续调用 checkIfAllowedAndInitiateInstall 方法

private void checkIfAllowedAndInitiateInstall() { ## 首先检查安装应用程序的用户限制,如果有限制并弹出弹出提示Dialog或者跳转到设置界面 final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource( UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle()); if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) { showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER); return; } else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) { startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); finish(); return; } // 判断如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源 if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) { initiateInstall(); } else { // 检查未知安装源限制,如果有限制弹出Dialog,显示相应的信息 final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle()); final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle()); final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource); if (systemRestriction != 0) { showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER); } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) { startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) { startAdminSupportDetailsActivity( UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY); } else { // 处理未知来源的APK handleUnknownSources(); } } }

主要检查安装应用程序的用户限制,当 APK 文件不对或者安装有限制则调用 showDialogInner 方法,弹出 dialog 提示用户,显示相应的错误信息,来看一下都有那些错误信息

// Dialog identifiers used in showDialog private static final int DLG_BASE = 0; // package信息错误 private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2; // 存储空间不够 private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3; // 安装错误 private static final int DLG_INSTALL_ERROR = DLG_BASE + 4; // 用户限制的未知来源 private static final int DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER = DLG_BASE + 5; private static final int DLG_ANONYMOUS_SOURCE = DLG_BASE + 6; // 在wear上不支持 private static final int DLG_NOT_SUPPORTED_ON_WEAR = DLG_BASE + 7; private static final int DLG_EXTERNAL_SOURCE_BLOCKED = DLG_BASE + 8; // 安装限制用户使用的应用程序 private static final int DLG_INSTALL_APPS_RESTRICTED_FOR_USER = DLG_BASE + 9;

如果用户允许安装未知来源,会调用 initiateInstall 方法

private void initiateInstall() { String pkgName = mPkgInfo.packageName; // 检查设备上是否存在相同包名的APK 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; } // 检查package是否已安装, 如果已经安装则显示对话框提示用户是否替换。 try { mAppInfo = mPm.getApplicationInfo(pkgName, PackageManager.MATCH_UNINSTALLED_PACKAGES); if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { mAppInfo = null; } } catch (NameNotFoundException e) { mAppInfo = null; } // 初始化确认安装界面 startInstallConfirm(); }

根据包名获取应用程序的信息,调用 startInstallConfirm 方法初始化安装确认界面后,当用户点击确认按钮之后发生了什么,接着查看确认按钮点击事件

private void bindUi() { ... // 点击确认按钮,安装APK mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install), (ignored, ignored2) -> { if (mOk.isEnabled()) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); finish(); } else { // 启动Activity来完成应用的安装 startInstall(); } } }, null); // 点击取消按钮,取消此次安装 mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel), (ignored, ignored2) -> { // Cancel and finish setResult(RESULT_CANCELED); if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } finish(); }, null); setupAlert(); mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); mOk.setEnabled(false); }

当用户点击确认按钮调用了 startInstall 方法,启动子 Activity 完成 APK 的安装

private void startInstall() { // 启动子Activity来完成应用的安 Intent newIntent = new Intent(); newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo); newIntent.setData(mPackageURI); newIntent.setClass(this, InstallInstalling.class); ... if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI); startActivity(newIntent); finish(); }

startInstall 方法用来跳转到 InstallInstalling,并关闭掉当前的 PackageInstallerActivity

3.3 InstallInstalling

主要工作:

向包管理器发送包的信息,然后等待包管理器处理结果 注册一个观察者 InstallEventReceiver,并接受安装成功和失败的回调 在方法 onResume 中创建同步栈,打开安装 session,设置安装进度条

InstallInstalling 首先向包管理器发送包的信息,然后等待包管理器处理结果,并在方法 InstallSuccess 和方法 InstallFailed 进行成功和失败的处理,查看 InstallInstalling 的 onCreate 方法:

protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... // 判断安装的应用是否已经存在 if ("package".equals(mPackageURI.getScheme())) { try { getPackageManager().installExistingPackage(appInfo.packageName); launchSuccess(); } catch (PackageManager.NameNotFoundException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } else { final File sourceFile = new File(mPackageURI.getPath()); PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile); ... if (savedInstanceState != null) { // 如果savedInstanceState 不为空,获取已经存在mSessionId 和mInstallId 重新注册 mSessionId = savedInstanceState.getInt(SESSION_ID); mInstallId = savedInstanceState.getInt(INSTALL_ID); try { // 根据mInstallId向InstallEventReceiver注册一个观察者,launchFinishBasedOnResult会接收到安装事件的回调 InstallEventReceiver.addObserver(this, mInstallId, this::launchFinishBasedOnResult); } catch (EventResultPersister.OutOfIdsException e) { } } else { // 如果为空创建SessionParams,代表安装会话的参数 // 解析APK, 并将解析的参数赋值给SessionParams PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); ... try { // 注册InstallEventReceiver,并在launchFinishBasedOnResult会接收到安装事件的回调 mInstallId = InstallEventReceiver .addObserver(this, EventResultPersister.GENERATE_NEW_ID, this::launchFinishBasedOnResult); } catch (EventResultPersister.OutOfIdsException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } try { // createSession 内部通过IPackageInstaller与PackageInstallerService进行进程间通信, // 最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId mSessionId = getPackageManager().getPackageInstaller().createSession(params); } catch (IOException e) { launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null); } } ... } }

最终都会注册一个观察者 InstallEventReceiver,并在 launchFinishBasedOnResult 会接收到安装事件的回调,其中 InstallEventReceiver 继承自 BroadcastReceiver,用于接收安装事件并回调给 EventResultPersister createSession 内部通过 IPackageInstaller 与 PackageInstallerService 进行进程间通信,最终调用的是 PackageInstallerService的createSession 方法来创建并返回 mSessionId 接下来在 onResume 方法创建 InstallingAsyncTask 用来执行 APK 的安装,接着查看 onResume 方法

protected void onResume() { super.onResume(); if (mInstallingTask == null) { PackageInstaller installer = getPackageManager().getPackageInstaller(); // 根据mSessionId 获取SessionInfo, 代表安装会话的详细信息 PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId); if (sessionInfo != null && !sessionInfo.isActive()) { mInstallingTask = new InstallingAsyncTask(); mInstallingTask.execute(); } else { // 安装完成后会收到广播 mCancelButton.setEnabled(false); setFinishOnTouchOutside(false); } } }

得到 SessionInfo 创建并创建 InstallingAsyncTask,InstallingAsyncTask 的 doInBackground 方法设置安装进度条,并将 APK 信息写入 PackageInstaller.Session,写入完成之后,在 InstallingAsyncTask 的 onPostExecute 进行成功与失败的处理,接着查看 onPostExecute 方法

protected void onPostExecute(PackageInstaller.Session session) { if (session != null) { Intent broadcastIntent = new Intent(BROADCAST_ACTION); broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntent.setPackage(getPackageName()); broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId); PendingIntent pendingIntent = PendingIntent.getBroadcast( InstallInstalling.this, mInstallId, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT); session.commit(pendingIntent.getIntentSender()); mCancelButton.setEnabled(false); setFinishOnTouchOutside(false); } else { getPackageManager().getPackageInstaller().abandonSession(mSessionId); if (!isCancelled()) { launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null); } } }

创建了 broadcastIntent,并通过 PackageInstaller.Session 的 commit 方法发送出去,通过 broadcastIntent 构造方法指定的 Intent 的 Action 为 BROADCAST_ACTION,而 BROADCAST_ACTION 是一个常量值

private static final String BROADCAST_ACTION = "com.android.packageinstaller.ACTION_INSTALL_COMMIT";

回到 InstallInstalling.OnCreate 方法,在 OnCreate 方法注册 InstallEventReceiver,而 InstallEventReceiver 继承自 BroadcastReceiver,而使用 BroadcastReceiver 需要在 AndroidManifest.xml注册,接着查看 AndroidManifest.xml: /frameworks/base/packages/PackageInstaller/AndroidManifest.xml

安装结束之后,会在观察者 InstallEventReceiver 注册的回调方法 launchFinishBasedOnResult 处理安装事件的结果,接着查看 launchFinishBasedOnResult

private void launchFinishBasedOnResult(int statusCode, int legacyStatus, String statusMessage) { if (statusCode == PackageInstaller.STATUS_SUCCESS) { launchSuccess(); } else { launchFailure(legacyStatus, statusMessage); } } private void launchSuccess() { Intent successIntent = new Intent(getIntent()); successIntent.setClass(this, InstallSuccess.class); successIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); startActivity(successIntent); finish(); } private void launchFailure(int legacyStatus, String statusMessage) { Intent failureIntent = new Intent(getIntent()); failureIntent.setClass(this, InstallFailed.class); failureIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); failureIntent.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, legacyStatus); failureIntent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, statusMessage); startActivity(failureIntent); finish(); }

安装成功和失败,都会启动一个新的 Activity(InstallSuccess、InstallFailed)将结果展示给用户,然后 finish 掉 InstallInstalling 总结一下 PackageInstaller 安装APK的过程: 现在来总结下PackageInstaller初始化的过程:

根据Uri的Scheme协议不同,跳转到不同的界面,content协议跳转到InstallStart,其他的跳转到PackageInstallerActivity。本文应用场景中,如果是Android7.0以及更高版本会跳转到InstallStart。

InstallStart将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity。

PackageInstallerActivity会分别对package协议和file协议的Uri进行处理,如果是file协议会解析APK文件得到包信息PackageInfo。 点击 OK 按钮确认安装后,会调用 startInstall 开始安装工作 如果用户允许安装,然后跳转到 InstallInstalling,进行 APK 的安装工作 在 InstallInstalling 中,向包管理器发送包的信息,然后注册一个观察者 InstallEventReceiver,并接受安装成功和失败的回调

PackageInstallSession

Android通过PackageInstallerSession来表示一次安装过程,一个PackageInstallerSession包含一个系统中唯一的一个SessionId,如果一个应用的安装必须分几个阶段来完成,即使设备重启了,也可以通过这个ID来继续安装过程

PackageInstallerService

安装的远程服务类,用于返回sessionid

@Override public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) { if (hasParentSessionId()) { throw new IllegalStateException( "Session " + sessionId + " is a child of multi-package session " + getParentSessionId() + " and may not be committed directly."); } if (!markAsSealed(statusReceiver, forTransfer)) { return; } if (isMultiPackage()) { synchronized (mLock) { final IntentSender childIntentSender = new ChildStatusIntentReceiver(mChildSessions.clone(), statusReceiver) .getIntentSender(); boolean sealFailed = false; for (int i = mChildSessions.size() - 1; i >= 0; --i) { // seal all children, regardless if any of them fail; we'll throw/return // as appropriate once all children have been processed if (!mChildSessions.valueAt(i) .markAsSealed(childIntentSender, forTransfer)) { sealFailed = true; } } if (sealFailed) { return; } } } dispatchSessionSealed(); } /** * Kicks off the install flow. The first step is to persist 'sealed' flags * to prevent mutations of hard links created later. */ private void dispatchSessionSealed() { mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget(); } private final Handler.Callback mHandlerCallback = new Handler.Callback() { @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_ON_SESSION_SEALED: handleSessionSealed(); break; case MSG_STREAM_VALIDATE_AND_COMMIT: handleStreamValidateAndCommit(); break; case MSG_INSTALL: handleInstall(); break; case MSG_ON_PACKAGE_INSTALLED: final SomeArgs args = (SomeArgs) msg.obj; final String packageName = (String) args.arg1; final String message = (String) args.arg2; final Bundle extras = (Bundle) args.arg3; final IntentSender statusReceiver = (IntentSender) args.arg4; final int returnCode = args.argi1; args.recycle(); sendOnPackageInstalled(mContext, statusReceiver, sessionId, isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, packageName, returnCode, message, extras); break; case MSG_SESSION_VALIDATION_FAILURE: final int error = msg.arg1; final String detailMessage = (String) msg.obj; onSessionValidationFailure(error, detailMessage); break; } return true; } };

经过一系列处理最终是调用的还是Pms中的安装方法

private void installNonStaged() throws PackageManagerException { final PackageManagerService.InstallParams installingSession = makeInstallParams(); if (installingSession == null) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session should contain at least one apk session for installation"); } if (isMultiPackage()) { final List childSessions; synchronized (mLock) { childSessions = getChildSessionsLocked(); } List installingChildSessions = new ArrayList(childSessions.size()); boolean success = true; PackageManagerException failure = null; for (int i = 0; i < childSessions.size(); ++i) { final PackageInstallerSession session = childSessions.get(i); try { final PackageManagerService.InstallParams installingChildSession = session.makeInstallParams(); if (installingChildSession != null) { installingChildSessions.add(installingChildSession); } } catch (PackageManagerException e) { failure = e; success = false; } } if (!success) { final IntentSender statusReceiver; synchronized (mLock) { statusReceiver = mRemoteStatusReceiver; } sendOnPackageInstalled(mContext, statusReceiver, sessionId, isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null, failure.error, failure.getLocalizedMessage(), null); return; } mPm.installStage(installingSession, installingChildSessions); } else { mPm.installStage(installingSession); } } packageManagerService final void startCopy() { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this); handleStartCopy(); handleReturnCode(); } @Override void handleReturnCode() { processPendingInstall(); } private void processPendingInstall() { InstallArgs args = createInstallArgs(this); if (mRet == PackageManager.INSTALL_SUCCEEDED) { mRet = args.copyApk(); } if (mRet == PackageManager.INSTALL_SUCCEEDED) { F2fsUtils.releaseCompressedBlocks( mContext.getContentResolver(), new File(args.getCodePath())); } if (mParentInstallParams != null) { mParentInstallParams.tryProcessInstallRequest(args, mRet); } else { PackageInstalledInfo res = createPackageInstalledInfo(mRet); processInstallRequestsAsync( res.returnCode == PackageManager.INSTALL_SUCCEEDED, Collections.singletonList(new InstallRequest(args, res))); } } // Queue up an async operation since the package installation may take a little while. private void processInstallRequestsAsync(boolean success, List installRequests) { mHandler.post(() -> { List apexInstallRequests = new ArrayList(); List apkInstallRequests = new ArrayList(); for (InstallRequest request : installRequests) { if ((request.args.installFlags & PackageManager.INSTALL_APEX) != 0) { apexInstallRequests.add(request); } else { apkInstallRequests.add(request); } } // Note: supporting multi package install of both APEXes and APKs might requir some // thinking to ensure atomicity of the install. if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) { // This should've been caught at the validation step, but for some reason wasn't. throw new IllegalStateException( "Attempted to do a multi package install of both APEXes and APKs"); } if (!apexInstallRequests.isEmpty()) { if (success) { // Since installApexPackages requires talking to external service (apexd), we // schedule to run it async. Once it finishes, it will resume the install. Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests), "installApexPackages"); t.start(); } else { // Non-staged APEX installation failed somewhere before // processInstallRequestAsync. In that case just notify the observer about the // failure. InstallRequest request = apexInstallRequests.get(0); notifyInstallObserver(request.installResult, request.args.observer); } return; } if (success) { for (InstallRequest request : apkInstallRequests) { request.args.doPreInstall(request.installResult.returnCode); } synchronized (mInstallLock) { installPackagesTracedLI(apkInstallRequests); } for (InstallRequest request : apkInstallRequests) { request.args.doPostInstall( request.installResult.returnCode, request.installResult.uid); } } for (InstallRequest request : apkInstallRequests) { restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult, new PostInstallData(request.args, request.installResult, null)); } }); } 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); Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token); Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0); mHandler.sendMessage(msg); } case POST_INSTALL: { if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1); PostInstallData data = mRunningInstalls.get(msg.arg1); final boolean didRestore = (msg.arg2 != 0); mRunningInstalls.delete(msg.arg1); if (data != null && data.res.freezer != null) { data.res.freezer.close(); } if (data != null && data.mPostInstallRunnable != null) { data.mPostInstallRunnable.run(); } else if (data != null && data.args != null) { InstallArgs args = data.args; PackageInstalledInfo parentRes = data.res; final boolean killApp = (args.installFlags & PackageManager.INSTALL_DONT_KILL_APP) == 0; final boolean virtualPreload = ((args.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0); handlePackagePostInstall(parentRes, killApp, virtualPreload, didRestore, args.installSource.installerPackageName, args.observer, args.mDataLoaderType);

www.edrawmax.cn/online/shar…

Android 12 针对使用 PackageInstaller API 的应用引入了 setRequireUserAction() 方法。此方法可让安装程序应用执行应用更新而无需用户确认操作。

@UserActionRequirement private int computeUserActionRequirement() { final String packageName; synchronized (mLock) { if (mPermissionsManuallyAccepted) { return USER_ACTION_NOT_NEEDED; } packageName = mPackageName; } final boolean forcePermissionPrompt = (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0 || params.requireUserAction == SessionParams.USER_ACTION_REQUIRED; if (forcePermissionPrompt) { return USER_ACTION_REQUIRED; } // It is safe to access mInstallerUid and mInstallSource without lock // because they are immutable after sealing. final boolean isInstallPermissionGranted = (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, mInstallerUid) == PackageManager.PERMISSION_GRANTED); final boolean isSelfUpdatePermissionGranted = (mPm.checkUidPermission(android.Manifest.permission.INSTALL_SELF_UPDATES, mInstallerUid) == PackageManager.PERMISSION_GRANTED); final boolean isUpdatePermissionGranted = (mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGE_UPDATES, mInstallerUid) == PackageManager.PERMISSION_GRANTED); final boolean isUpdateWithoutUserActionPermissionGranted = (mPm.checkUidPermission( android.Manifest.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION, mInstallerUid) == PackageManager.PERMISSION_GRANTED); final int targetPackageUid = mPm.getPackageUid(packageName, 0, userId); final boolean isUpdate = targetPackageUid != -1 || isApexSession(); final InstallSourceInfo existingInstallSourceInfo = isUpdate ? mPm.getInstallSourceInfo(packageName) : null; final String existingInstallerPackageName = existingInstallSourceInfo != null ? existingInstallSourceInfo.getInstallingPackageName() : null; final boolean isInstallerOfRecord = isUpdate && Objects.equals(existingInstallerPackageName, getInstallerPackageName()); final boolean isSelfUpdate = targetPackageUid == mInstallerUid; final boolean isPermissionGranted = isInstallPermissionGranted || (isUpdatePermissionGranted && isUpdate) || (isSelfUpdatePermissionGranted && isSelfUpdate); final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID); final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID); // Device owners and affiliated profile owners are allowed to silently install packages, so // the permission check is waived if the installer is the device owner. final boolean noUserActionNecessary = isPermissionGranted || isInstallerRoot || isInstallerSystem || isInstallerDeviceOwnerOrAffiliatedProfileOwner(); if (noUserActionNecessary) { return USER_ACTION_NOT_NEEDED; } if (mPm.isInstallDisabledForPackage(getInstallerPackageName(), mInstallerUid, userId)) { // show the installer to account for device poslicy or unknown sources use cases return USER_ACTION_REQUIRED; } if (params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED && isUpdateWithoutUserActionPermissionGranted && (isInstallerOfRecord || isSelfUpdate)) { return USER_ACTION_PENDING_APK_PARSING; } return USER_ACTION_REQUIRED; } private PackageManagerService.VerificationParams prepareForVerification() throws PackageManagerException { assertNotLocked("makeSessionActive"); @UserActionRequirement int userActionRequirement = USER_ACTION_NOT_NEEDED; // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc if (!params.isMultiPackage) { userActionRequirement = computeUserActionRequirement(); if (userActionRequirement == USER_ACTION_REQUIRED) { sendPendingUserActionIntent(); return null; } // else, we'll wait until we parse to determine if we need to } boolean silentUpdatePolicyEnforceable = false; synchronized (mLock) { if (mRelinquished) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session relinquished"); } if (mDestroyed) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed"); } if (!mSealed) { throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed"); } PackageLite result = parseApkLite(); if (result != null) { mPackageLite = result; synchronized (mProgressLock) { mInternalProgress = 0.5f; computeProgressLocked(true); } extractNativeLibraries( mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs()); 1 安装程序声明了 UPDATE_PACKAGES_WITHOUT_USER_ACTION 权限。 2 正在安装的应用程序的目标是 API 级别 29(Android 10)或更高 if (userActionRequirement == USER_ACTION_PENDING_APK_PARSING) { if (result.getTargetSdk() < Build.VERSION_CODES.Q) { sendPendingUserActionIntent(); return null; } 3 安装器选择了新的行为 不需要操作的行为 if (params.requireUserAction == SessionParams.USER_ACTION_NOT_REQUIRED) { silentUpdatePolicyEnforceable = true; } } } } if (silentUpdatePolicyEnforceable) { if (!mSilentUpdatePolicy.isSilentUpdateAllowed( getInstallerPackageName(), getPackageName())) { // Fall back to the non-silent update if a repeated installation is invoked within // the throttle time. sendPendingUserActionIntent(); return null; } 记录静默更新程序 mSilentUpdatePolicy.track(getInstallerPackageName(), getPackageName()); } synchronized (mLock) { return makeVerificationParamsLocked(); } } private PackageManagerService.VerificationParams makeVerificationParamsLocked() { final IPackageInstallObserver2 localObserver; if (!hasParentSessionId()) { // Avoid attaching this observer to child session since they won't use it. 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) { if (returnCode == INSTALL_SUCCEEDED) { onVerificationComplete(); } else { onSessionVerificationFailure(returnCode, msg); } } }; } else { localObserver = null; } private void onVerificationComplete() { // Staged sessions will be installed later during boot if (isStaged()) { // TODO(b/136257624): Remove this once all verification logic has been transferred out // of StagingManager. mStagingManager.notifyPreRebootVerification_Apk_Complete(mStagedSession); // TODO(b/136257624): We also need to destroy internals for verified staged session, // otherwise file descriptors are never closed for verified staged session until reboot return; } install(); }

直接执行安装

new.qq.com/omn/2021052…

本文转自 www.jianshu.com/p/4e9c6e5fc…,如有侵权,请联系删除。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3