Android PackageManager enable any application - android

I have developed an application in which I have enabled that any application which we have can be installed manually
But my problem is that I only want to enable my own package name and rather not any other application package name.
Here is the code I have used.
try {
PackageManager pm1 = getPackageManager();
pm1.setComponentEnabledSetting(new ComponentName("com.service",
"com.service.EnableActivity"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
);
} catch (SecurityException e) {
e.printStackTrace();
}
here "com.service" is the package name that I install and "com.service.EnableActivity" is my first app launcherActivity.
Log
java.lang.SecurityException: Permission Denial: attempt to change component state from pid=3354, uid=10056, package uid=10058 at
android.os.Parcel.readException(Parcel.java:1322) at
android.os.Parcel.readException(Parcel.java:1276) at
android.content.pm.IPackageManager$Stub$Proxy.setComponentEnabledSettingIPackageManager.java:2217)
But when I use the same application packagename and classname then it's working fine.

Add this code in your both applications mainfest.
<manifest
.......
.......
.......
android:sharedUserLable="...."
android:sharedUserID="...">
because it need a userid to be same
This will help you.

Looking at the platform I see the following:
<!-- Allows an application to change whether an application component (other than its own) is
enabled or not. -->
<permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
android:label="#string/permlab_changeComponentState"
android:description="#string/permdesc_changeComponentState"
android:protectionLevel="signatureOrSystem" />
Note that because this is "signatureOrSystem" (and it is declared in the system) it can only be used by apps that are signed with the system signature, in other words you need to be an Android vendor (HTC, Samsung, Motorola, etc). See this for more info:
http://developer.android.com/guide/topics/manifest/permission-element.html
UPDATE:
Gurjinder Singh Pabla has the right answer, if you are trying to change the enabled state of your own components or applications then you need to ensure that they have the same user id, which is set in the AndroidManifest. You only need to be a Vendor if you want to disable other packages that have different user ids. You can see the check in the Android source in PackageManagerService.java is:
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
// ...
if (!allowedByPermission && (uid != pkgSetting.userId)) {
throw new SecurityException(
"Permission Denial: attempt to change component state from pid="
+ Binder.getCallingPid()
+ ", uid=" + uid + ", package uid=" + pkgSetting.userId);
}

Related

Checking if a DIFFERENT app is granted a permission

I've read around the internet for two options to check if an app is granted a permission or not.
Option 1:
getPackageManager().checkPermission(permission_string, packageName);
Option 2:
(PackageInfo.requestedPermissionsFlag[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0
I'm running on Android 11. I'm implementing a mechanism that upon clicking an app, the permissions state will be checked and if a permission is not allowed, the user will be prompt to allow it. I'm only checking this for "advanced" permissions, meaning, permissions that requires the user to allow them from settings screen, such as manage external storage (for android 11), drawOverlay, writeSettings and such. Anyway, this is the code I'm using:
try {
PackageInfo pi = getPackageManager().getPackageInfo(currAppInfo.getName(), PackageManager.GET_PERMISSIONS);
for(int i=0; i<pi.requestedPermissions.length; i++)
{
String perm = pi.requestedPermissions[i];
PermissionInfo permi = getPackageManager().getPermissionInfo(perm, PackageManager.GET_META_DATA);
if(getPackageManager().checkPermission(perm, currAppInfo.getName()) == 0)
continue;
if(AdvancedPermissionHandler.isAdvancedPermission(permi))
{
AdvancedPermissionHandler.openSettingsPage(permi, currAppInfo.getName(), MainActivity.this);
return;
}
}
} catch (Exception e) {
e.printStackTrace();
}
The only problem I'm facing is that even if I'm using option 1 and even if I'm using option 2, I'm ALWAYS getting false on the check. Meaning, say I click an app that requires manage external storage and it's state is currently not allowed. I click the app, I get moved to the appropriate screen, I allow the permission, I go back to the main screen, when I click the app again, instead of opening, I'm being moved to the same permission screen. Debugger shows that
getPackageManager().checkPermission(permission_string, packageName);
is returning false, even though the permission is given. Same for when I'm using option 2.
So my question is, what other methods are available to determine if a different app is granted a permission or, what am I doing wrong here in this code.
After digging some more I've found AppOps.
This is the code I've used to work, Android 11:
AppOpsManager appOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(currAppInfo.getName(), 0);
PackageInfo pi = getPackageManager().getPackageInfo(currAppInfo.getName(), PackageManager.GET_PERMISSIONS);
for(int i=0; i<pi.requestedPermissions.length; i++)
{
String perm = pi.requestedPermissions[i];
PermissionInfo permi = getPackageManager().getPermissionInfo(perm, PackageManager.GET_META_DATA);
if(AppOpsManager.permissionToOp(permi.name) == null)
continue;
boolean granted = (appOps.unsafeCheckOpNoThrow(AppOpsManager.permissionToOp(permi.name),applicationInfo.uid,currAppInfo.getName()) == AppOpsManager.MODE_ALLOWED);
if(granted)
continue;
}
This is due to Android 11 restrictions to prevent installed apps fingerprinting.
You need to add target package name (e.g com.termux) to queries element or declare QUERY_ALL_PACKAGES permission in AndroidManifest.xml if targetSdkVersion is 30+. Check Package Visibility or this article for more info. Otherwise, you will will get PackageSetting{...... com.termux/......} BLOCKED errors in logcat.
<manifest
<queries>
<package android:name="com.termux" />
</queries>
</manifest>

Permission Denial of android.intent.action.REBOOT for APP in /system/priv-app

A feature of my app is designed to send a reboot broadcast when a Reboot button is clicked.
getActivity().sendBroadcast(new Intent(Intent.ACTION_REBOOT));
According to Android reference documents, apps whose APKs are in /system/priv-app directory are allowed to use signatureOrSystem permissions without sharing the platform cert. Refer to AOSP Privileged vs System app
The REBOOT permission is one of them (in frameworks/base/core/res/AndroidManifest.xml).
<!-- #SystemApi Required to be able to reboot the device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.REBOOT"
android:label="#string/permlab_reboot"
android:description="#string/permdesc_reboot"
android:protectionLevel="signature|system" />
So I signed my APK with my own cert then pushed my APK to /system/priv-app and made sure the APK file has same read-write access permission as other APKs in the directory.
However, it failed to send a reboot broadcast with an error as followed,
ActivityManager: Permission Denial: not allowed to send broadcast android.intent.action.REBOOT from pid=2801, uid=10016
I checked system statuses with dumpsys and found that the REBOOT permission was granted for the user-id of 10016.
SharedUser [com.example] (10b8d16d):
userId=10016 gids=[1028, 1015, 1007, 3003]
grantedPermissions:
android.permission.REBOOT
BTW, I'm using a pad of Android5.1.1 for the testing.
I got the answer in ActivityManagerService.java from Android source code.
int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
|| callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
|| callingAppId == Process.NFC_UID || callingUid == 0) {
// Always okay.
} else if (callerApp == null || !callerApp.persistent) {
try {
if (AppGlobals.getPackageManager().isProtectedBroadcast(
intent.getAction())) {
String msg = "Permission Denial: not allowed to send broadcast "
+ intent.getAction() + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
...
}
...
}
}
So, android:persistent NEED be set to true.
<application android:name="MyApp"
android:persistent="true">
According to docs, you can't use it.
Broadcast Action: Have the device reboot. This is only for use by
system code.
This is a protected intent that can only be sent by the system.
https://developer.android.com/reference/android/content/Intent.html#ACTION_REBOOT

How come a GCM permission isn't granted on Android 6?

Background
I'm trying to investigate what an app at the office needs to change about its permissions, in order to support Android 6 nicely.
The problem
I've found which permission needs confirmation and which isn't, except for one :
<uses-permission android:name=".permission.C2D_MESSAGE"/>
It seems that this permission isn't mentioned anywhere that I look for, as one that's not granted automatically and yet I can't find where the user can enable it as a confirmation.
What I tried
In order to find which permissions are granted by default and which aren't , I just called this code:
private void checkPermissionsOfApp(String packageName) {
PackageManager pm = getPackageManager();
try {
final ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
Log.d("AppLog", "Listing all permissions of app with PackageName: " + applicationInfo.packageName);
PackageInfo packageInfo = pm.getPackageInfo(applicationInfo.packageName, PackageManager.GET_PERMISSIONS);
//Get Permissions
String[] requestedPermissions = packageInfo.requestedPermissions;
if (requestedPermissions != null) {
for (String permission : requestedPermissions) {
boolean permissionGranted = pm.checkPermission(permission, packageName) == PackageManager.PERMISSION_GRANTED;
Log.d("AppLog", "permission:" + permission + " permissionGranted:" + permissionGranted);
}
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
And the call:
checkPermissionsOfApp(getPackageName());
Using the above code, it crashes for the problematic permission, but when using ContextCompat.checkSelfPermission it says it's not granted.
The question
How could it be?
How can I grant the app this permission?
Is it mentioned anywhere?
The documentation, which was updated in October of 2015, still indicates that you need the signature permission.
See also Not receiving push notifications from GCM (Android)
As #CommonsWare mentioned, this does not appear to be part of the new runtime permission checking, or at least is not considered a "dangerous" permission, and so should be automatically granted.
ok, I'm not sure why it is this way, but the permission is said to be granted only if :
The package name of the app is its prefix
you also declare the permission, as such:
<permission
android:name="com.example.user.androidmtest.permission.C2D_MESSAGE"
android:protectionLevel="signature"/>
The weird thing is that even though the code said that the permission is not granted when not adding the package name, it worked on the app.

Can an app determine the other apps that are on the phone and what permissions they have?

I'm wondering if an app has access to the info that shows the other apps on the phone and what permissions they have (i.e. access to your location, contacts, etc). Could I create an app with a feature that displays other apps and their permissions? I know the user can view this info via settings, but I'm wondering if it can be organized and displayed by an app.
Yes. Use the PackageManager. Call GetInstalledPackages to list the installed packages, and then check the requestedPermissions field to see the permissions for each package.
Note: the method below assumes this refers to an Activity.
private void getAppPermissions() {
List<PackageInfo> apps = this.getPackageManager().getInstalledPackages(PackageManager.GET_PERMISSIONS);
for (PackageInfo app : apps) {
String appInfo = app.packageName + ": ";
String[] permissions = app.requestedPermissions;
if (null == permissions) {
appInfo += "no permissions requested\n";
} else {
for (String permission : app.requestedPermissions) {
appInfo += "\n " + permission;
}
}
Log.v("App Permissions", appInfo);
}
}
You may wish to filter the list of returned packages as per this question.
Yes you can. For Android, you just go to Settings > Applications
And you just tap on the application that you want to check, and on the bottom it should say the permissions the app possesses.
For ios, you go to Settings > Privacy
And you tap on the desired type of permission, and you can see the apps that have that permission.

Android checkCallingOrSelfPermission not returning properly

I am writing a service which needs to see if its caller holds a particular private permission. I do not want to prevent callers that lack this permission, I only want to know the status so that I can react accordingly. It would seem that the Context method checkCallingPermission() is perfect for what I need, returning 0 if the caller has the specified permission and -1 otherwise. I'm finding that -1 is returned in all cases though.
I wrote a test case (using the similar method checkCallingOrSelfPermission() where I pulled my package's PackageInfo from the system, enumerated each of my permissions (only one requested for the package), and display the result of checkCallingOrSelfPermission(). Since the permissions I'm checking against in this case are exactly the permissions I hold, I would expect checkCallingOrSelfPermission() to return 0 (PackageManager.PERMISSION_GRANTED) only... buy it only returns -1 (PackageManager.PERMISSION_DENIED).
I've checked this and received the same results on both a 4.0 emulator and a 2.3 device.
Any idea what I'm doing wrong to cause these calls to fail?
My test manifest includes:
<permission
android:protectionLevel="signatureOrSystem"
android:name="abcd" />
<uses-permission android:name="abcd" />
My test activity code is:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PackageManager pm = getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo("com.test.check", PackageManager.GET_PERMISSIONS);
if ((null == pi.requestedPermissions) ||
(pi.requestedPermissions.length == 0)) {
Log.d("CHECK", "Package has NO permissions!");
finish();
return;
}
for (int i = 0; i < pi.requestedPermissions.length; ++i) {
Log.d("CHECK", pi.requestedPermissions[i] + " " + checkCallingOrSelfPermission(pi.requestedPermissions[i]));
}
} catch (NameNotFoundException e) {
Log.d("CHECK", "Package name is wrong!");
}
finish();
}
and my test results are:
D/CHECK ( 3600): abcd -1
I have not been able to resolve this within the scope of my service needing to check permissions, but I have found a work-around for the service (and a problem in my test case).
My test case failed because the permission I created and checked with, "abcd", was renamed by Android in the <permission> entry, however Android failed to equally rename it in the <uses-permission> entry. It was renamed to have my package name prepended to it (and this renaming does not occur if I provide a name including a period in it, such as "test.abcd").
Though changing the permission name fixed my test case, my actual case within a service was already using a fully qualified permission name and checkCallingPermission() continues to fail. I discovered, however, that the PackageManager's checkPermission() method does work as expected (at the expense of my needing to retrieve the name of the caller's package).
So to summarize, the following does not work correctly (though I do not know why):
boolean permission = (PackageManager.PERMISSION_GRANTED == checkCallingPermission(PERMISSION_NAME));
while this seems to work correctly:
PackageManager pm = getPackageManager();
boolean permission = (PackageManager.PERMISSION_GRANTED == pm.checkPermission(PERMISSION_NAME, pm.getNameForUid(getCallingUid())));

Categories

Resources