Я создал приложение, которое должно иметь возможность удалять приложения на устройстве.Приложение подписано соответствующим сертификатом платформы и имеет следующие разрешения:
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);
Обе функции работают для приложений, которые были установлены вручную или с помощью следующей команды
Runtime.getRuntime().exec("pm install -r -i my.package.name --user 0 pathTo.apk");
Если я пытаюсь удалить приложение, установленное через PlayStore, происходит сбой.Это не дает ошибки.Также я не вижу подсказок в 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.
Я использовал Pixel с AOSP 8.1 и два пользовательских устройства.Мое приложение всегда подписывалось соответствующим сертификатом платформы.
РЕШЕНИЕ:
Мне пришлось добавить android: sharedUserId = "android.uid.system" в мой манифест Android.Я немного покопался в источнике android и нашел функцию
PackageManagerService.isCallerAllowedToSilentlyUninstall
Эта проверка вызывается при вызове PackageManager.deletePackage.Из исходного кода я понял, что наличие разрешения android.permission.DELETE_PACKAGES недостаточно для удаления приложений, которые были установлены другим приложением (playstore).Это разрешено только 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;
}
....
Наличие System UID - единственная возможность получить предоставленную операцию (за исключением пакетов, которые были установлены моим собственным приложением.)