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.