API 23 has renamed permission protection level system into privileged. It has also introduced a preinstalled protection level.
Does privileged implies preinstalled? In other words, if an application has access to privileged permissions (i.e. it is a system application), does it have access to preinstalled permissions as well, even if those permissions are not listed as privileged (only preinstalled)?
It's possible for apps to be pre-installed but not have elevated system permissions (e.g. Calculator). This is why the distinction is present between these two flags and why system protection level has been deprecated for privileged.
The answer seems to be yes, as long as a privileged app is part of the system image (i.e. pre-installed). The package manager will grant a preinstalled permission to what it (internally) calls a system app, see grantSignaturePermission():
if (!allowed && (bp.protectionLevel
& PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0
&& isSystemApp(pkg)) {
// Any pre-installed system app is allowed to get this permission.
allowed = true;
}
Internally, a system app is actually a pre-installed app (refactoring is limited to the public API, not in the source), see ActivityInfo:
/**
* Value for {#link #flags}: if set, this application is installed in the
* device's system image.
*/
public static final int FLAG_SYSTEM = 1<<0;
// Many lines not shown
public boolean isSystemApp() {
return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
Related
I'm trying to get a list of apps (on Android 8.0+) that have REQUEST_INSTALL_PACKAGES permissions marked as granted.
context.packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS or PackageManager.GET_META_DATA).forEach { pi ->
if (pi.requestedPermissions != null) {
for (i in pi.requestedPermissions.indices) {
if (pi.requestedPermissions[i] == android.Manifest.permission.REQUEST_INSTALL_PACKAGES) {
if ((pi.requestedPermissionsFlags[i] and PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
// permission is granted, do stuff here
}
}
}
}
}
The problem is, that corresponding requestedPermissionsFlags entry is always 1, which means REQUESTED_PERMISSION_REQUIRED and that is obviously wrong.
I tried different api: context.packageManager.checkPermission(android.Manifest.permission.REQUEST_INSTALL_PACKAGES, pi.packageName) == PackageManager.PERMISSION_GRANTED with the same result.
In tried this on Android 8, 9 and 10 on different devices and the only success I had was on Pixel 3a that came positive for com.android.nfc. Others were always false even when I can see in system settings that chrome and other apps have this permission granted.
Am I missing something for this API? Is it private? There is not much to find about it.
Because this permmission has a signature protection level. According to documentation:
A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission
So requestedPermissionsFlags is correct - only com.android.nfc is granted.
Actually REQUEST_INSTALL_PACKAGES has a signature|appop protection level, that's why not only system apps can use it although this perrmission is not granted for them. For a little bit more details - Acquiring Android Permission with Signature Protection Level.
I need to grant my device permission to change automation settings of the device it is running on (for testing purpose).
I have added to manifest:
<uses-permission android:name="android.permission.SET_ANIMATION_SCALE"/>
And in my Activity on resume:
String[] permissions = new String[1];
permissions[0] = Manifest.permission.SET_ANIMATION_SCALE;
ActivityCompat.requestPermissions(getCurrentActivity(), permissions, 0);
Log.d("ISGRANTED", " " + (ContextCompat.checkSelfPermission(getCurrentActivity(), permissions[0]) == PackageManager.PERMISSION_GRANTED));
And nothing happens. I test on Android Api 23+ and I don't get any dialog to get the permission. Log returns:
06-30 15:03:32.757 17771-17799/my.app.package D/ISGRANTED: false
But if I replace permisions[0] with Manifest.permission.GET_ACCOUNTS (which is also in my manifest above SET_ANIMATION_SCALE permission) then it works. Dialog appears and log returns true.
What's the problem?
Please take a look at my Gradle plugin, Cappuccino. It automates the process of disabling system animations for Espresso testing. There are detailed instructions on Github.
From here or here, because it's not for use by third-party applications:
"android.permission.SET_ANIMATION_SCALE" : ["signature|system|development", "Modify the global animation scaling factor. Not for use by third-party applications."],
ProtectionLevel (from here):
signature 2 A permission that the system is to grant only if the requesting application is signed with the same certificate as the application that declared the permission. If the certificates match, the system automatically grants the permission without notifying the user or asking for the user's explicit approval.
system 0x10 Old synonym for "privileged".
privileged 0x10 Additional flag from base permission type: this permission can also be granted to any applications installed as privileged apps on the system image. Please avoid using this option, as the signature protection level should be sufficient for most needs and works regardless of exactly where applications are installed. This permission flag is used for certain special situations where multiple vendors have applications built in to a system image which need to share specific features explicitly because they are being built together.
development 0x20 Additional flag from base permission type: this permission can also (optionally) be granted to development applications.
I want to know if my app's camera permission is granted or not. Then I written the below functions, but they are always return incorrect result. Not matter how can I disabled the camera permission of my app in system settings, the both functions always return TRUE. Do you know something wrong in my codes?
public static boolean checkCameraPermission() {
String permission = "android.permission.CAMERA";
int res = App.getInstance().checkCallingOrSelfPermission(permission);
return (res == PackageManager.PERMISSION_GRANTED);
}
public static boolean checkCameraPermission(Context context) {
PackageManager pm = context.getPackageManager();
boolean permission = (PackageManager.PERMISSION_GRANTED ==
pm.checkPermission("android.permission.CAMERA", pm.getNameForUid(Binder.getCallingUid())));
return permission;
}
I want to know if my app's camera permission is granted or not
If your targetSdkVersion is 23 or higher, and you are running on an Android 6.0+ device, use checkSelfPermission(). The native implementation of checkSelfPermission() is on Context; ContextCompat has a version that will not crash on older Android devices.
If your targetSdkVersion is 22 or lower, or you are running on an Android 5.1 or older device, you always have your requested permissions (exception: possibly some custom ROMs).
If your targetSdkVersion is 22 or lower, and you are running on an Android 6.0 or higher device, you also always have your requested permissions, in terms of the methods that you are calling as outlined in your question. The user, in Settings, can block your access to data associated with those permissions, but technically the user is not actually revoking the permissions themselves (though we often say they are just to keep the explanation simple). I know of no way for you to determine that the user is blocking your camera access, other than by catching the relevant exceptions when you attempt to access the camera. Note that those exceptions will be raised in other scenarios (e.g., camera access is blocked by device policy).
I'm developing an application that going to be pr-installed (as a system app) on the firmware.
from the documentation so far about the relation between system apps, new permissions model, and the protection levels - I don't understand exactly when system app needs (if at all) to request user permission.
My problems starts when I try to use the WRITE_EXTERNAL_STORAGE permission. from the documentation I can see that it marked as "dangerous" permission.
- does "dangerous" permissions grant automatically to system apps?
when I use WRITE_EXTERNAL_STORAGE permission (as a system app) I'm getting security exception, and I don't know if it's mean that even tough my app installed as a system app - "dangerous" permissions must be requested by the user..
another point to mention:
to check the app behavior as a system app, I'm installing my application APK on the sys-priv directory (the device is rooted) of a nexus 5 running SDK preview 3. this is when I'm getting the security exception when attep to use methods requires the external storage permission..
After a lot of digging and debugging, I finally found some clue of granting runtime permission on marshmallow for system app, with a lot of inspirations in this stackoverflow ticket.
The key logic is in DefaultPermissionGrantPolicy. After systemReady, PackageManagerService checks if this user's default runtime permissions are not set yet(i.e. this is a new user), if so, PackageManagerService calls DefaultPermissionGrantPolicy.grantDefaultPermissions() to check/grant permissions:
public void grantDefaultPermissions(int userId) {
grantPermissionsToSysComponentsAndPrivApps(userId);
grantDefaultSystemHandlerPermissions(userId);
}
There are two cases that your built-in app may be automatically granted with runtime permission.
A> grantPermissionsToSysComponentsAndPrivApps -> will grant runtime permission with FLAG_PERMISSION_SYSTEM_FIXED and FLAG_PERMISSION_GRANTED_BY_DEFAULT.
if your system app has uid<10000, you will be granted with permissions for your user group.
if your system app fits all below conditions, it will be granted the permissions.
is a privilegedApp (under /system/priv-app/)
is persistent (android:persistent="true")
signed with platform signature.
B> grantDefaultSystemHandlerPermissions -> will grant runtime permission with FLAG_PERMISSION_GRANTED_BY_DEFAULT .
If your app is considered as a "default platform handler app", (i.e. your app is "expected to work out-of-the-box", like camera, dialer, SMS, calendar .etc, you can read more in method grantDefaultSystemHandlerPermissions()).
Other than that, your system application needs to ask user for granting dangerous permission, as long as it has targetSdk set to 23.
Quoting the release notes for the 2nd M preview:
Apps included in the system image are no longer granted dangerous permissions automatically. All apps should check for and request permissions at runtime.
That fits with what I recall seeing when I first used the stock Camera app on a Nexus 5 with the final(?) 6.0 preview firmware — it too asked for the runtime permission.
So, AFAIK, system apps have to ask for runtime permissions, as do non-system apps.
So in 4.3 there was a concept of System applications. APKs that were placed in /system/app were given system privileges. As of 4.4, there is a new concept of "privileged app". Privileged apps are stored in /system/priv-app directory and seem to be treated differently. If you look in the AOSP Source code, under PackageManagerService, you will see new methods such as
static boolean locationIsPrivileged(File path) {
try {
final String privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app")
.getCanonicalPath();
return path.getCanonicalPath().startsWith(privilegedAppDir);
} catch (IOException e) {
Slog.e(TAG, "Unable to access code path " + path);
}
return false;
}
So here is an example of a situation where these differ.
public final void addActivity(PackageParser.Activity a, String type) {
...
if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
intent.setPriority(0);
Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
+ a.className + " with priority > 0, forcing to 0");
}
...
This affects the priority of any activities that are not defined as system applications. This seems to imply you can not add an activity to the package manager whose priority is higher than 0, unless you are a system app. This does not preclude privileged apps as far as I can tell (there is a lot of logic here, I may be wrong.).
My question is what exactly does this imply? If my app is privileged, but not system, what difference will that make? In PackageManagerService you can find various things that differ between system and privileged apps, they are not exactly the same. There should be some kind of ideology behind privileged apps, otherwise they would have just said:
if locationIsPrivileged: app.flags |= FLAG_SYSTEM
and been done with it. This is a new concept, and I think it would be important to know the difference between these kinds of apps for anyone who is doing AOSP development as of 4.4.
So after some digging, it's clear that apps in priv-app are eligible for system permissions, the same way that old apps used to be eligible to claim system permissions by being in system-app. The only official Google documentation I could find on this came in the form of a commit message:
Commit hash: ccbf84f44c9e6a5ed3c08673614826bb237afc54
Some system apps are more system than others
"signatureOrSystem" permissions are no longer available to all apps
residing en the /system partition. Instead, there is a new
/system/priv-app directory, and only apps whose APKs are in that
directory are allowed to use signatureOrSystem permissions without
sharing the platform cert. This will reduce the surface area for
possible exploits of system- bundled applications to try to gain
access to permission-guarded operations.
The ApplicationInfo.FLAG_SYSTEM flag continues to mean what it is says
in the documentation: it indicates that the application apk was
bundled on the /system partition. A new hidden flag FLAG_PRIVILEGED
has been introduced that reflects the actual right to access these
permissions.
Update: As of Android 8.0 priv-app has changed slightly with the addition of Privileged Permission Whitelisting. Beyond just being in priv-app, your app must also be added to a whitelist in order to gain various system permissions. Information on this can be found here: https://source.android.com/devices/tech/config/perms-whitelist