Several questions about shutting down a rooted android device have answers saying you should run "reboot -p" within an "su" shell. However, this answer says that reboot is quite low-and-dirty and doesn't do sufficient tidying up before pulling the plug. Instead it recommends using android.internal.app.ShutdownThread.shutdown(). Looking at the code I can see that this does a whole bunch of housekeeping stuff that I'd like to have, and it also has a handy "confirm" parameter that appears to let you shut down without asking for confirmation, which is nice.
My question is this - what properties does an app have to have in order to call ShutdownThread.shutdown()? Does is require a particular permission that can be set if the device is rooted, or does it have to be signed using the firmware key, or something else entirely?
Shutting down the device requires you to hold android.permission.SHUTDOWN which is only available to system applications, or applications signed with the platform certificate.
Related
Background: I am developing for a signage device which is to be remotely operated. I need an application that can
Fetch and install new packages
Reboot the device (for troubleshooting)
I have an unrooted Android device. I also have files which I am told are the platform keys.
I have developed an application which attempts to kick off the su process.
Process p = Runtime.getRuntime().exec("su");
Before I signed the application with the platform keys this was throwing an IOException, with the message being Permission Denied.
I signed the application with these platform keys, and I am still getting the Permission Denied exception.
Here are three contradictory statements. Which one of these statements (if any) is correct?
Statment 1: This should work. The application, even though is is stored in /data/app, should be able to run su. Either I have the wrong keys, or there's some other entry I need to add to the manifest to get it to work.
Statement 2: This shouldn't work. Even though it is signed with the platform key, the application is in /data/app, so it's a data application, not a system application. Data applications cannot run su on an unrooted devices. If this application was installed into /system/app, then it would be able to run su. (And I can't get it into /system/app because it's unrooted, so I'm stuck).
Statment 3: This will never work. If the device is not rooted, then NOTHING can run su, even if it is a signed system app.
Android shouldn't even have a su binary if you didn't flash some sort of root method to the device, such as Magisk or SuperSU.
Even if it does have a su binary, I wouldn't expect it to work, for one of two reasons. Assuming that your device comes with a preinstalled su binary, who's managing it? If it's unmanaged, it should just deny all requests. If you flash a root method, then it's up to that manager to decide if your app gets access to su, regardless of whether you have signature-level permissions or nor (the root manager uses a different signature, after all).
And why would you even need access to su as a signature app? You have total access to the device anyway. If you need to run a command, you should have no problems no matter what you run, as long as it's done from your platform-signed package. But since you have full access, the native APIs should let you do everything you need.
As for the IOException returned when you try to execute su in a Process, that's just a weird Android quirk. If there's no su binary installed, it'll sometimes return command not found and other times permission denied, depending on the device.
The point I think I'm making is that, unless your app is the root manager, you could be part of the system_server and still have the same access to su as everyone else. For which statement I agree with, I think #3, although I don't fully agree with it, because chances are su just doesn't exist, or it's a dud binary.
I've explained why #1 shouldn't be true, but #2 is just incorrect. If you look at the platform manifest, every permission that requires a privileged app can also be granted to signature apps. So even if you did move your app to /system/priv-app/ (/system/app/ won't make it privileged), it wouldn't make a difference. Basically, if your app is signed by the platform signature, it doesn't matter where it's installed.
EDIT:
You can easily reboot by just running reboot as a command, since you have signature-level access to the system, but it's a little more elegant to use the proper API for this. If you use the API, you get the shutdown animation, but you also let the system shut down gracefully, stopping services and sending the ACTION_REBOOT broadcast to any apps that might be listening for that.
To use the API, first add the following permission to your AndroidManifest:
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
Now, where you need to call the reboot action, use the following code:
IStatusBarService bar = IStatusBarService.Stub.asInterface(ServiceManager.getService(Context.STATUS_BAR_SERVICE));
bar.reboot(false); //using true here will reboot to Safe Mode
This method is a hidden method, so if you're using Android Studio to edit and compile, it'll error out. You can use reflection, or use Android Hidden API to access it directly.
This is how System UI implements it in the power menu: https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
This is the class that implements IStatusBar service: https://github.com/aosp-mirror/platform_frameworks_base/blob/master/services/core/java/com/android/server/statusbar/StatusBarManagerService.java#L969
I'd go with Statement 3. This will never work on an unrooted Android device. At least, not on recent Android OS versions (I have no idea if this might work on really old Android devices).
"su" is an application -- there has to be an "su" binary on disk in order to execute it, and Android does not by default provide an "su" binary for security purposes. When you use thirdparty rootkits, they install their own "su" binary to provide a mechanism for the user to elevate themselves to root privileges.
If your app is signed with a special key and granted elevated privileges from startup, why would you need to execute "su" anyway?
At work, we have an Android-based infotainment system that we're constantly deploying new versions to, on a half-dozen different test benches. The deployment script does the moral equivalent of:
for apk in ${apk_files}; do
adb install -r ${apk]
done
After this, we need to manually execute the following steps:
Set the home app to be one of our just-installed applications (Always, not Just Once)
Become a developer, and enable the Stay Awake option
Select the Google TTS engine for text-to-speech functionality rather than Pico
Executing these steps after each deploy is a giant PITA. People often forget one or more steps, and leave the test bench in a non-working state. This results in a bunch of 'bogus' bug reports that waste everbody's time.
Is there some way (using adb, perhaps) that we can automate these steps?
You can disable other home apps with adb shell pm disable .... I don't think there's a command line option to set apps as default. I remember looking into this before and there was a "preferred application" XML file where this was stored. If you want to look into it, the magic happens in PackageManagerService.addPreferredActivityInternal(). Looks like it writes the data to a file on disk: package-restrictions.xml. I suppose it's possible you could figure out the format thereof and write the file (you'd need root).
This is controlled by a system settings, "stay_on_while_plugged_in". You can set it using adb shell settings system put ....
The TTS engine is stored in a secure setting, "tts_default_synth". You can see the value like,
$ adb shell settings get secure tts_default_synth com.svox.pico
com.svox.pico
And you can set it with adb shell settings put secure "tts_default_synth" <the value>.
I noticed that if the value was not been previously set, when you get the value using the settings command you get null and it's not listed in settings list, even though there is a default value. As of Android 6 (I think), settings are no longer in a DB but rather are stored in XML files in /data/system/users/0/settings_*.xml. You can see the values therein.
I recently jumped into an android development tutorials and doing my own app for the sake of learning. I want to get root permissions within my code in a proper way. So not by calling /system/xbin/su but by using something like seteuid(0). Unfortunately seteuid method does not work for me.
I am testing app on a real device, which I rooted, enabled debugging mode and well I clearly see that when using a call to /system/xbin/su my app requests root permissions from system, which does not happen with seteuid and seteguid (setuid and setguid do not work either but I would not expect those to do it as they are capable only in lowering the permissions).
Please, advice on where to look for a proper code implementation for requesting root permissions like it would do a top notch developer. Maybe some native api call? Or does everyone just use a call to su to get the needed access?
The usual way in Linux of elevating privileges -- that is, to run an application with greater privileges than the logged-in user -- is to set the SUID flag on the executable (e.g., chmod ug+s ...). This will make the process take the identity of the binary's owner (usually root), rather than the logged-in user.
This is tricky to do effectively on Android, even on a rooted device. First, you won't be able to install an app using the usual (APK) mechanisms that includes binaries with SUID permissions. Second, an Android app is not an executable in the usual sense -- a single executable handles the launching of all apps.
Still, if you want to experiment on the command line, it should be possible to set the SUID flag on binaries, in at least some filesystem locations.
If you have a rooted Android, then very likely there is some infrastructure already in place to control privilege elevation. Most likely the "su" command will work (because there will be kernel mods to make it work), and it will be provided either with credentials or with some other way to control which apps can use it. I believe that, as you suggest, calling "su" is the usual way to do privilege elevation in apps on rooted Android. It is fraught with difficulties, however. There's a document https://su.chainfire.eu/ that explains how "su" is typically implemented in rooted Android devices, and gives some guidance on how to use it properly.
Just in case posting my solution to the problem which I did in Java (no native code is needed here):
protected void hideRoot() throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream dos = new DataOutputStream(p.getOutputStream());
dos.writeBytes("mount -o remount,rw /system\n");
dos.writeBytes("mv /system/xbin/su /system/xbin/suhidden\n");
dos.writeBytes("exit\n");
dos.flush();
p.waitFor();
}
There is a bug on some Samsung Android Phones causing USB-debugging to automatically be turned on if the USB is plugged in. This is obviously a security issue. I want to write a program which will disable USB debugging so that I can start it whenever usb-plug is inserted.
Any ideas on how to do this?
It seems to be impossible. I think I must use Settings.System with ADB_ENABLED, but ADB_ENABLED is a Secure-System-Setting which cannot be changed by a normal application. :-(
On the other hand, there is the permission android.permission.WRITE_SECURE_SETTINGS, so it looks like I can alter it. Can I get it on a rooted phone?
If someone has an idea on how to fix this security issue, it would be great.
I don't think it is a security issue.
First, it is the responsibility of a developer to only make debug messages available that do not compromise his application in the later.
Secondly, debug messages that are used for development should probably have another debug level than for production.
Third, if your application exposes data via adb that compromisses your application, maybe there's something wrong in the app design in the beginning?
Fourth: It is not recommended to toggle settings that the user should be able to configure. I would hate to see manything I configured go on and off by starting an app. Of course, you mentioned the Bug with Samsung. But I think they should be able to fix this.
Regards, Chris
To achieve this , you require android.permission.WRITE_SECURE_SETTINGS permission.
Without root : From ABD execute adb shell pm grant <package-name> android.permission.WRITE_SECURE_SETTINGS
With root : Root access means we can execute shell commands without adb, so workaround for that :
try {
Runtime.getRuntime().exec(new String[]{"su","-c",String.format("pm grant %s android.permission.WRITE_SECURE_SETTINGS",BuildConfig.APPLICATION_ID)});
} catch (IOException e) {
// handle IOException
}
I need to be able to toggle the GPS receiver on and off, and WRITE_SECURE_SETTINGS is required to be able to access secure settings. I've searched around quite a bit, and every answer I saw pretty much said that no app outside of the system/firmware can get that permisssion.
However, that is simply untrue. There are several apps on the market that do exactly what I'm trying to (in regards to GPS), but there are a bunch more that have the WRITE_SECURE_SETTINGS permissions. For example:
Extended Controls
SwitchPro
Profile Flow
So, how can this be done?
I need to be able to toggle the GPS receiver on and off
For privacy reasons, if nothing else, enabling or disabling any sort of location-tracking needs to be solely in the hands of the user via trusted applications, not at the request of arbitrary third parties.
So, if you wish to enable and disable GPS, create your own firmware that does what you need and load that firmware on whatever devices you wish. Or, contribute your changes to existing firmware mods (e.g., Cyanogen).
WRITE_SECURE_SETTINGS is required to be able to access secure settings
Correct.
I've searched around quite a bit, and every answer I saw pretty much said that no app outside of the system/firmware can get that permisssion.
Correct.
However, that is simply untrue.
No, it's pretty true.
There are several apps on the market that do exactly what I'm trying to (in regards to GPS)
They found a security loophole. I will take steps to help ensure this hole gets fixed.
but there are a bunch more that have the WRITE_SECURE_SETTINGS permissions
No, there are a bunch who ask for them. You can ask for whatever permission you want. What you ask for is what shows up in these listings. What you get is a different story.
Try this adb command, this will give permission at application run time
adb shell pm grant package android.permission.WRITE_SECURE_SETTINGS
Step to follow:
Connect your device (Make sure USB Debugging enabled)
Execute above adb command
Install apk
It worked for me...
Just this. You can access the widget that every mobile have.
public void ativaGPS() {
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Intent intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.widget.SettingsAppWidgetProvider");
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
intent.setData(Uri.parse("3"));
sendBroadcast(intent);
}