4

Is it possible to check if another app can install unknown sources? prior to Oreo the following code worked:

int isUnknownAllowed = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 0);
return isUnknownAllowed == 1

In Oreo, the permission is granted per-app as described in the documentation, and the check is now:

getPackageManager().canRequestPackageInstalls()

But this only returns whether the current app can install packages.

Can I check if another app has this permission?

TheWanderer
  • 16,775
  • 6
  • 49
  • 63
BennyP
  • 1,737
  • 1
  • 18
  • 24

1 Answers1

0

The implementation of canRequestPackageInstalls() uses the internal API IPackageManager, which actually takes a package name argument:

@Override
public boolean canRequestPackageInstalls() {
    try {
        return mPM.canRequestPackageInstalls(mContext.getPackageName(), mContext.getUserId());
    } catch (RemoteException e) {
        throw e.rethrowAsRuntimeException();
    }
}

Using reflection or a modified SDK JAR, it's possible to call API directly (note: if your app targets Android 9 or later, you'll need to bypass the hidden API restrictions):

IPackageManager.Stub.asInterface(ServiceManager.getService("package")).canRequestPackageInstalls("some.package.name", context.userId)

Unfortunately, the underlying PackageManagerService has a check that prevents normal apps from checking other apps' install status:

private boolean canRequestPackageInstallsInternal(String packageName, int flags, int userId,
        boolean throwIfPermNotDeclared) {
    int callingUid = Binder.getCallingUid();
    int uid = getPackageUid(packageName, 0, userId);
    if (callingUid != uid && callingUid != Process.ROOT_UID
            && callingUid != Process.SYSTEM_UID) {
        throw new SecurityException(
                "Caller uid " + callingUid + " does not own package " + packageName);
    }
    ...
}

Unless your app's UID and the UID of the package name you pass match (or your app is root or a system app), you can't check other apps.

There is a workaround for this, which works best on Android 11 or later: use Shizuku. Shizuku lets you call Java APIs with ADB/shell permissions, which should let you use the API:

IPackageManager.Stub.asInterface(SystemServiceWrapper(SystemServiceHelper.getService("package"))).canRequestPackageInstalls("some.package.name", context.userId)

If you need a silent/zero-interaction way to check, I don't think you can without root access.

TheWanderer
  • 16,775
  • 6
  • 49
  • 63