安卓系统应用的卸载和恢复(非data分区)

您所在的位置:网站首页 miui删除文件恢复 安卓系统应用的卸载和恢复(非data分区)

安卓系统应用的卸载和恢复(非data分区)

2024-07-05 06:16:41| 来源: 网络整理| 查看: 265

安卓系统应用的卸载和恢复(非data分区) Uninstall and Restore Android System Apps (non-data partition)

网上已经有很多预装应用卸载的方法了,但是他们基本都是设法在第一次开机的时候安装到data分区。

本文需要达到的目标是预装在system分区的应用能够被卸载,且能恢复安装。

命令行方法

安卓5.0开始可以针对用户卸载系统应用

卸载系统应用 adb shell pm uninstall -k --user 0 app包名

-k是是否需要保留数据,可以不加。

恢复系统应用

安卓7开始才可以通过命令恢复

adb shell cmd package install-existing app包名 代码方法 代码分析(基于目前aosp master分支最新代码) 卸载

com/android/server/pm/PackageManagerShellCommand.java

private int runUninstall() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); int flags = 0; int userId = UserHandle.USER_ALL; long versionCode = PackageManager.VERSION_CODE_HIGHEST; String opt; while ((opt = getNextOption()) != null) { switch (opt) { case "-k": flags |= PackageManager.DELETE_KEEP_DATA; break; case "--user": userId = UserHandle.parseUserArg(getNextArgRequired()); break; case "--versionCode": versionCode = Long.parseLong(getNextArgRequired()); break; default: pw.println("Error: Unknown option: " + opt); return 1; } } final String packageName = getNextArg(); if (packageName == null) { pw.println("Error: package name not specified"); return 1; } / if a split is specified, just remove it and not the whole package ArrayList splitNames = getRemainingArgs(); if (!splitNames.isEmpty()) { return runRemoveSplits(packageName, splitNames); } // 不加--user是卸载所有用户的应用 if (userId == UserHandle.USER_ALL) { flags |= PackageManager.DELETE_ALL_USERS; } final int translatedUserId = translateUserId(userId, UserHandle.USER_SYSTEM, "runUninstall"); final LocalIntentReceiver receiver = new LocalIntentReceiver(); final PackageManagerInternal internal = LocalServices.getService(PackageManagerInternal.class); if (internal.isApexPackage(packageName)) { internal.uninstallApex( packageName, versionCode, translatedUserId, receiver.getIntentSender(), flags); } else { //如果删除某一个用户的应用,走这里 if ((flags & PackageManager.DELETE_ALL_USERS) == 0) { final PackageInfo info = mInterface.getPackageInfo(packageName, PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, translatedUserId); if (info == null) { pw.println("Failure [not installed for " + translatedUserId + "]"); return 1; } final boolean isSystem = (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; // If we are being asked to delete a system app for just one // user set flag so it disables rather than reverting to system // version of the app. if (isSystem) { flags |= PackageManager.DELETE_SYSTEM_APP; } } mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName, versionCode), null /*callerPackageName*/, flags, receiver.getIntentSender(), translatedUserId); } final Intent result = receiver.getResult(); final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); if (status == PackageInstaller.STATUS_SUCCESS) { pw.println("Success"); return 0; } else { pw.println("Failure [" + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); return 1; } }

android/content/pm/PackageInstaller.java

/** * Uninstall the given package with a specific version code, removing it * completely from the device. If the version code of the package * does not match the one passed in the versioned package argument this * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to * uninstall the latest version of the package. *

* This method is available to: * * the current "installer of record" for the package * the device owner * the affiliated profile owner * * * @param versionedPackage The versioned package to uninstall. * @param statusReceiver Where to deliver the result. * * @see android.app.admin.DevicePolicyManager */ @RequiresPermission(anyOf = { Manifest.permission.DELETE_PACKAGES, Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull VersionedPackage versionedPackage, @NonNull IntentSender statusReceiver) { uninstall(versionedPackage, 0 /*flags*/, statusReceiver); } /** * Uninstall the given package with a specific version code, removing it * completely from the device. This method is only available to the current * "installer of record" for the package. If the version code of the package * does not match the one passed in the versioned package argument this * method is a no-op. Use {@link PackageManager#VERSION_CODE_HIGHEST} to * uninstall the latest version of the package. * * @param versionedPackage The versioned package to uninstall. * @param flags Flags for uninstall. * @param statusReceiver Where to deliver the result. * * @hide */ @RequiresPermission(anyOf = { Manifest.permission.DELETE_PACKAGES, Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull VersionedPackage versionedPackage, @DeleteFlags int flags, @NonNull IntentSender statusReceiver) { Objects.requireNonNull(versionedPackage, "versionedPackage cannot be null"); try { //binder调用 mInstaller.uninstall(versionedPackage, mInstallerPackageName, flags, statusReceiver, mUserId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }

com/android/server/pm/PackageInstallerService.java

@Override public void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags, IntentSender statusReceiver, int userId) { final Computer snapshot = mPm.snapshotComputer(); final int callingUid = Binder.getCallingUid(); snapshot.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall"); if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) { mAppOps.checkPackage(callingUid, callerPackageName); } // Check whether the caller is device owner or affiliated profile owner, in which case we do // it silently. DevicePolicyManagerInternal dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); final boolean canSilentlyInstallPackage = dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid); final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, statusReceiver, versionedPackage.getPackageName(), canSilentlyInstallPackage, userId); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) { // Sweet, call straight through! mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); } else if (canSilentlyInstallPackage) { // Allow the device owner and affiliated profile owner to silently delete packages // Need to clear the calling identity to get DELETE_PACKAGES permission final long ident = Binder.clearCallingIdentity(); try { mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); } finally { Binder.restoreCallingIdentity(ident); } DevicePolicyEventLogger .createEvent(DevicePolicyEnums.UNINSTALL_PACKAGE) .setAdmin(callerPackageName) .write(); } else { ApplicationInfo appInfo = snapshot.getApplicationInfo(callerPackageName, 0, userId); if (appInfo.targetSdkVersion >= Build.VERSION_CODES.P) { mContext.enforceCallingOrSelfPermission(Manifest.permission.REQUEST_DELETE_PACKAGES, null); } // Take a short detour to confirm with user final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE); intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null)); intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder()); adapter.onUserActionRequired(intent); } }

com/android/server/pm/IPackageManagerBase.java

@Override @Deprecated public final void deletePackageAsUser(String packageName, int versionCode, IPackageDeleteObserver observer, int userId, int flags) { deletePackageVersioned(new VersionedPackage(packageName, versionCode), new PackageManager.LegacyPackageDeleteObserver(observer).getBinder(), userId, flags); } 恢复安装

com/android/server/pm/PackageManagerShellCommand.java

private int runInstallExisting() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); int userId = UserHandle.USER_CURRENT; int installFlags = PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; String opt; boolean waitTillComplete = false; while ((opt = getNextOption()) != null) { switch (opt) { case "--user": userId = UserHandle.parseUserArg(getNextArgRequired()); break; case "--ephemeral": case "--instant": installFlags |= PackageManager.INSTALL_INSTANT_APP; installFlags &= ~PackageManager.INSTALL_FULL_APP; break; case "--full": installFlags &= ~PackageManager.INSTALL_INSTANT_APP; installFlags |= PackageManager.INSTALL_FULL_APP; break; case "--wait": waitTillComplete = true; break; case "--restrict-permissions": installFlags &= ~PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS; break; default: pw.println("Error: Unknown option: " + opt); return 1; } } final String packageName = getNextArg(); if (packageName == null) { pw.println("Error: package name not specified"); return 1; } final int translatedUserId = translateUserId(userId, UserHandle.USER_NULL, "runInstallExisting"); int installReason = PackageManager.INSTALL_REASON_UNKNOWN; try { if (waitTillComplete) { final LocalIntentReceiver receiver = new LocalIntentReceiver(); final IPackageInstaller installer = mInterface.getPackageInstaller(); pw.println("Installing package " + packageName + " for user: " + translatedUserId); installer.installExistingPackage(packageName, installFlags, installReason, receiver.getIntentSender(), translatedUserId, null); final Intent result = receiver.getResult(); final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); pw.println("Received intent for package install"); return status == PackageInstaller.STATUS_SUCCESS ? 0 : 1; } //走这里 final int res = mInterface.installExistingPackageAsUser(packageName, translatedUserId, installFlags, installReason, null); if (res == PackageManager.INSTALL_FAILED_INVALID_URI) { throw new NameNotFoundException("Package " + packageName + " doesn't exist"); } pw.println("Package " + packageName + " installed for user: " + translatedUserId); return 0; } catch (RemoteException | NameNotFoundException e) { pw.println(e.toString()); return 1; } } 系统应用反射调用接口进行卸载和恢复

虽然命令从安卓5.0才开始支持,但接口应该是从安卓4.2(支持多用户)就开始支持了:

//安卓8以前 public void deletePackageAsUser(final String packageName, final IPackageDeleteObserver observer, final int userId, final int flags) public int installExistingPackageAsUser(String packageName, int userId) //安卓8开始 public void deletePackageAsUser(String packageName, int versionCode, IPackageDeleteObserver observer, int userId, int flags) public int installExistingPackageAsUser(String packageName, int userId, int installFlags,int installReason) 怎么做

系统应用可以通过android.content.pm.IPackageManager$Stub反射分别获得deletePackageAsUser和installExistingPackageAsUser,前者可以卸载,后者可以恢复安装。恢复安装之前可以通过packageManager.getApplicationInfo判断系统是否还存在安装包,否则可以跳应用商店进行安装。

注意:

1、deletePackageAsUser会清除数据,但不会卸载更新。即如果系统应用更新后,会存在两个apk,一个在system分区,一个在data分区。

如果要删除data下的更新,可以先调用卸载接口再调用deletePackageAsUser。

2、/data/dalvik-cache/下面会残留dex文件,可以扫描删除。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭