I was wondering if it's possible for third-party apps to dynamically add permission to the system or not. According to this book, it is possible through the use of the public addPermission() API; however, I am getting a SecurityException that says "java.lang.SecurityException: You either need MANAGE_USERS or CREATE_USERS permission to: query users". I just wanted to make sure it is really because the system doesn't allow it and not because I messed up something in my code. If it is the case, dynamic addition of permissions is not allowed to third-party apps not signed with the system certificate, it would be great if somebody could explain the reasoning behind this choice.
Here is how I add the permission programmatically:
public void addDynamicPermission() {
PermissionInfo pi = new PermissionInfo();
pi.name = "com.somedomain.permission.MY_PERMISSION";
pi.labelRes = R.string.permission_label;
pi.protectionLevel = PermissionInfo.PROTECTION_DANGEROUS;
final PackageManager packageManager = getApplicationContext().getPackageManager();
packageManager.addPermission(pi);
}
This is what I have in my manifest file:
<permission-tree android:name="com.somedomain.permission" />
and this is the full java stack for the exception:
FATAL EXCEPTION: main
Process: com.example.myapp, PID: 11824
java.lang.SecurityException: You either need MANAGE_USERS or CREATE_USERS permission to: query users
at android.os.Parcel.readException(Parcel.java:1684)
at android.os.Parcel.readException(Parcel.java:1637)
at android.content.pm.IPackageManager$Stub$Proxy.addPermission(IPackageManager.java:2870)
at android.app.ApplicationPackageManager.addPermission(ApplicationPackageManager.java:535)
at com.example.myapp.MainActivity.addDynamicPermission(MainActivity.java:183)
at com.example.myapp.MainActivity$6.onClick(MainActivity.java:64)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Thanks a lot!
TL;DR: The book is outdated and versions of Android newer than Lollipop do indeed require MANAGE_USERS or CREATE_USERS, both of which have a protectionLevel of 3 (signatureOrSystem).
Longer answer:
A while back, in the KitKat era, I wrote some test code similar to yours and I recall it working fine. That was a few years ago. I just fired up that old app in my current Nougat (7.0) environment and ended up with the exact same exception that you are seeing. Curious, I reinstalled KitKat (4.4.4), Lollipop (5.1), and Marshmallow (6.0) instances and tried the app on each.
For 4.4.4 and 5.1, everything works fine. I verified this by running the code and then checking for the existence of the custom permission as follows:
% adb shell dumpsys package packagename | grep -i com.example
...
Permission [com.example.permission.TEST_PERMISSION] (79c4d6d):
sourcePackage=com.example.myapplication
perm=Permission{2c725da2 com.example.permission.TEST_PERMISSION}
...
However, on 6.0 and 7.0, I'm getting the security exception. A quick check of androidxref.com indicates that the exception is coming from either the getPrimaryUser or getUsers method in UserManagerService.
getPrimaryUsers doesn't exist in 4.4.4 or 5.1, and getUsers has always been protected with checkManageOrCreateUsersPermission. Therefore, I think its reasonable to assume that the addPermission chain was modified starting in 6.0 to get a list of users for some reason. So addPermission does not require MANAGE_USERS or CREATE_USERS, but a method it now calls does.
Whether or not this additional access control check is intended and the reasoning behind why, are questions I cannot answer.
Related
I have an app that allows users to login using fingerprint authentication. The feature has been in production for a couple of months, but in the last day I started seeing many of these exceptions:
java.lang.SecurityException: Must have android.permission.USE_FINGERPRINT permission.: Neither user ##### nor current process has android.permission.USE_FINGERPRINT.
The crash occurs when I call fingerprintManager.isHardwareDetected() to check whether or not the device supports fingerprint authentication. I have the USE_FINGERPRINT permission declared in the manifest, so I don't know why the system would think that the process does not have this permission. This should not be something that I have to check at run time since USE_FINGERPRINT is a normal permission.
This has been working fine for months, and when it started crashing yesterday, we had been on a stable release for about a month. This problem sounds almost identical to this FingerprintManager.isHardwareDetected() throwing java.lang.SecurityException?. I am only seeing the crash on Oreo devices.
My current plan is to catch the Security Exception and proceed as if the device did not have the hardware, but my worry is that this might mean that no one is able to use the feature for login if this problem persists. Has anyone else had a recent issue with this exception? Or if not, does anyone have any ideas about why this might have just started happening all of a sudden like this? Thanks for the help!
Use the FingerprintManagerCompat instead, that was handling permissions correctly for me.
See:
https://developer.android.com/reference/android/support/v4/hardware/fingerprint/FingerprintManagerCompat
Additionally you might want to declare the permissions in your Android Manifest:
<!-- Fingerprint -->
<uses-permission-sdk-23 android:name="android.permission.USE_FINGERPRINT" />
Note that I used uses-permission-sdk-23, since I found that FingerprintManager doesn't work reliable in older versions of Android, I know there are some Samsung Galaxy devices with fingerprint reader, but before API 23 you were granting permissions at installation time; that depends more on your market. Try it and see if it makes a difference for your users.
See: https://developer.android.com/guide/topics/manifest/uses-permission-sdk-23-element
I am going to write a project that can hide another apps. I do research and find some useful code and it work well to hide my app. You can see my code below:
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
And the problem is that, I don't know how can I hide another apps. I have tried to do lot of research but I still cannot find any solution. So you can look at my code below (but it is not working to hide another apps, but to hide my own is working well):
PackageManager p = getPackageManager();
ComponentName com = new ComponentName("com.example.pro", "com.example.pro.classname");
p.setComponentEnabledSetting(com, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
I know that the first parameter for ComponentName is a package name of the app, and second parameter is a main activity name of the app that I want to hide. But it always force close every time i changed both of this parameters to another value. But if I change the first parameter to package name of my app and second parameter to the main activity name of my app, it work well like the first code I show above.
And I have some log that i got when my app force close below:
04-01 22:56:32.884 13339-13339/com.example.pro D/AndroidRuntime: Shutting down VM 04-01 22:56:32.884 13339-13339/com.example.pro E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.pro, PID: 13339
java.lang.SecurityException: Permission Denial: attempt to change component state from pid=13339, uid=10613, package uid=10464
at android.os.Parcel.readException(Parcel.java:1540)
at android.os.Parcel.readException(Parcel.java:1493)
at android.content.pm.IPackageManager$Stub$Proxy.setComponentEnabledSetting(IPackageManager.java:4073)
at android.app.ApplicationPackageManager.setComponentEnabledSetting(ApplicationPackageManager.java:1839)
at com.example.pro.MainActivity$1.onClick(MainActivity.java:142)
at android.view.View.performClick(View.java:5191)
at android.view.View$PerformClick.run(View.java:20931)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5944)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
So the problem is that, how can I hide another apps ? Any other code/method/suggest/example is fine. And i'd appreciate your help. Thanks.
I don't know how can I hide another apps
Fortunately, you cannot do that from an ordinary SDK app, for obvious security reasons. Ransomware authors would love the ability to do what you are proposing.
There are some hooks for doing what amounts to "hide another apps" in the device owner APIs IIRC, but they require the app be a device owner app, and that requires special work at the time the phone or tablet is first powered on after being purchased.
You may be able to accomplish what you want on a rooted device, and you certainly can do it with your own custom ROM. You could also create a home screen that "hides" apps by simply not showing them in its own launcher.
Background
We have a very large and very popular app with quite a few permissions.
The problem
It seems that on Motorola devices only (XT1254,XT1585,XT1565), with Android 5.1 and 5.1.1, we get crashes of this kind:
Fatal Exception: java.lang.SecurityException: Permission Denial: not allowed to send
broadcast com.motorola.intent.SYSTEM_DIALOG_POPUP from pid=15407, uid=10164
at android.os.Parcel.readException(Parcel.java:1546)
at android.os.Parcel.readException(Parcel.java:1499)
at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:2864)
at android.app.ContextImpl.sendBroadcast(ContextImpl.java:1510)
at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:382)
at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:382)
at android.app.Dialog$2.run(Dialog.java:316)
at android.os.Handler.handleCallback(Handler.java:746)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5356)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:905)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:700)
The above statistics were collected using Crashlytics.
Not sure if it is because of this, but one of the app's permission is "SYSTEM_ALERT_WINDOW", to be able to show content on top of other apps.
Thing is, this error seems to be because of Motorola's code itself, and I can't find anything about it over the Internet.
What I've tried
Apart from searching the Internet about this exception, I've also tried to find how to contact Motorola itself, including finding a developer forum, but I've failed in doing so.
I've also tried posting about this on Android's group:
https://code.google.com/p/android/issues/detail?id=201631
The question
What can be done in this case?
Why does it occur? Is it because of the permission? Is there a workaround ?
Hi actually me and my team mates faced the exact same problem when we were building an application which shows notes on top of other applications.
After researching for great lengths we found out that "SYSTEM_ALERT_WINDOW" permissions was made a signature permission and was causing problems by not letting the pop up appear from Lollipop 5.1
As a work around to it we need to explicitly ask the user to grant overlay permission for your app by doing this.
public void checkOverlayPermission(){
if(!Settings.canDrawOverlays(this)){
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:"+getPackageName()));
startActivityForResult(intent, ApplicationConstants.OVERLAY_PERMISSION);
}
}
Hope this helps
In my code I have:
Settings.System.putInt(this.getContentResolver(), "vibrate_when_ringing", isVibrateWhenRinging ? 1 :0);
Using the following permission:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
This was working fine from Jelly Bean (API 16) till Lollipop (API 22).
In Android M, I know that for using that permission I need to prompt the user to Settings.ACTION_MANAGE_WRITE_SETTINGS.
However, even with that permission turned on, I see the following error:
E/AndroidRuntime: java.lang.IllegalArgumentException: You cannot change private secure settings.
E/AndroidRuntime: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:165)
E/AndroidRuntime: at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:135)
E/AndroidRuntime: at android.content.ContentProviderProxy.call(ContentProviderNative.java:646)
Well... Am I missing something? With proper permissions we can change ringtones, do not disturb mode, etc. But it also looks like that with Android M we won't be able to change such a normal setting like "Vibrate when ringing". I hope I'm wrong.
You should call Settings.System.canWrite() to see that you can to write this setting.
If function returns false then the user can agree to allow your app to write to settings:
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getApplicationContext().getPackageName()));
startActivity(intent);
I am going to answer my own question. There is an issue opened to Google: https://code.google.com/p/android/issues/detail?id=194376.
Basically, they partially fixed vibrate_when_ringing and it works again on Android N (24). Unfortunately, it does not work on Android M (23). For the response on the issue, it does not seem that is going to be fixed.
You can see a full example repo here: https://github.com/ferrannp/VibrateWhenRinging
So, basically, your code needs to check if your on Android M and if you are, do not use that setting.
Jelly Bean has removed the ability to read the logs of other apps (according to this I/O talk), which is a sensible security improvement. However, I need to read ActivityManager-logs for my app to work (to see which app is currently starting). To do this, I was using
private static final String clearLogcat = "logcat -c";
private static final String logcatCommand = "logcat ActivityManager:I *:S";
//...
which no longer works, as I can only read my own application's logs in Jelly Bean. Is there an alternative solution to finding out when another app is starting (apart from root)? I understand why we shouldn't be able to read other applications' logs (kind of - it should be the other developers' resposibility to make sure that no personal information is logged, not mine by being prevented from reading the log), but I don't understand why the ActivityManager, a framework class, is included in that policy...
Thanks,
Nick
There is an extensive discussion of this issue going on here. Unfortunately, it's "expected behavior" and as such won't be fixed. The only current solution (for reading the logs from within an application on JB and above) is to manually grant the permission to the app through adb:
adb shell pm grant <pkg> android.permission.READ_LOGS
A such-granted permission:
survives reboots
survives application updates (i.e. "adb install -r")
does not survive if the application was uninstalled and then installed
again
It's obvious that this isn't something that a normal user can be expected to do. A GUI-solution (where users can grant this permission from the Settingsmenu of their device) is promised by the Android team, but unfortunately the functionality was removed before the "fix" was implemented.
First of all, ActivityManager isn't an application... it's a class that makes up part of the Android application framework.
Second of all, if the Android team deliberately went out of their way to prevent this from working, then I doubt there is a security loophole around it. The fact is that third party applications should not have to rely on logcat logs in order to work properly. If you give some details about your reason for needing to read these logs, maybe we can help point you to a better solution.