我创建了一个应能够在设备上卸载应用的应用。 该应用已使用适当的平台证书签名,并具有 授予以下权限
android.permission.DELETE_PACKAGES
android.permission.INTERACT_ACROSS_USERS_FULL
android.permission.INSTALL_PACKAGES
android.permission.MANAGE_USERS
要卸载软件包,应用程序将调用以下功能
PackageManager.deletePackageAsUser(packageName,observer,flags,userHandle);
或未设置用户句柄
PackageManager.deletePackage(packageName,observer,flags);
这两种功能均适用于手动安装或使用以下命令安装的应用apk。
Runtime.getRuntime().exec("pm install -r -i my.package.name --user 0 pathTo.apk");
如果我尝试卸载通过PlayStore安装的APS,它将失败。 它没有错误。另外,我在logcat中看不到任何提示。
我定义了一个观察者
IPackageDeleteObserver ob = new IPackageDeleteObserver() {
public void packageDeleted(String s, int i) throws RemoteException {
Log.e("dbg","s: " + s + " i:"+i);
}
public IBinder asBinder() {
Log.e("dbg","binder called");
return null;
}
};
卸载手动安装的apk时,两个函数都会被调用。 卸载由playstore安装的应用程序时,只会调用asBinder函数。
我在AOSP 8.1和两个自定义设备上使用了Pixel。 我的应用始终使用正确的平台证书签名。
解决方案:
我必须在Android清单中添加android:sharedUserId =“ android.uid.system”。我在android源代码中挖了一点,找到了函数
PackageManagerService.isCallerAllowedToSilentlyUninstall
当调用PackageManager.deletePackage时,将调用此检查。 从源代码中,我发现拥有android.permission.DELETE_PACKAGES权限还不足以卸载由另一个应用程序(播放商店)安装的应用程序。 仅允许PlayStore和PackageInstaller。
private boolean isCallerAllowedToSilentlyUninstall(int callingUid, String pkgName) {
if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID
|| UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
return true;
}
....
拥有系统UID是获得授予操作的唯一可能性(除了由我自己的应用程序安装的软件包之外)。