How to reset factory data programmatically in Android - android

How to do Android device factory data reset from application level?
I tried to run command with su, but it's not working. I have tried two ways:
1)
public void onClick(DialogInterface dialog, int which) {
try {
Process proc = Runtime.getRuntime().exec(new String[] { "su", "–wipe_data" });
proc.waitFor();
} catch (Exception ex) {}
}
2) when clicking a button, I'm calling device setting application, but I also did't get factory data reset.
startActivityForResult(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS), 0);
How to call settings->storage&reset->factory data reset directly from my app?

You should use the Intent.ACTION_MASTER_CLEAR to factory reset from your application. You might need to have appropriate permissions for your app (system/signed) to do this.
In case you don't have the required permissions / it's not possible for your app to get to the appropriate permission level, as an alternate, using am broadcast -a android.intent.action.MASTER_CLEAR from su shell might work.

Related

Android Pie (9.0) - Writing a Shutdown or Restart Function - Application is Privileged

I have a security system in schools, where my tablets are the consoles for each classroom. I've noticed teachers and admin are not restarting the tablets very often (or ever), which has caused issues. I would like to take the task from the clients and program a weekly reboot or shutdown. I have taken a few steps in the right direction:
I have:
Spoken with the Tablet Provider/Scheme Provider, and they have added my app as a privileged app.
Added a whitelist for (what I think are) all required permissions.
Confirmed the privileges exist.
Code to Check Permissions:
public void getGrantedPermissions(final String appPackage) {
List<String> granted = new ArrayList<String>();
try {
PackageInfo pi = getPackageManager().getPackageInfo(appPackage, PackageManager.GET_PERMISSIONS);
for (int i = 0; i < pi.requestedPermissions.length; i++) {
if ((pi.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
granted.add(pi.requestedPermissions[i]);
}
}
} catch (Exception e) {}
for(int i = 0; i < granted.size(); i++){
Log.e("Permissions", granted.get(i));
}
}
Below is what the log reported. The green permissions are all that I could get on my personal phone. The yellow permissions are what I was able to get, additionally, from the Tablet provider's whitelist. We can confirm by these permissions that I have a privileged app, as well as the shutdown and reboot permissions.
I was able to find a section of code to shutdown the app, but it seems that I can't quite figure out how to use it. Below is the code I have tried, and the error follows:
Intent intent = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
intent.putExtra("android.intent.extra.KEY_CONFIRM", false);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Error upon running code:
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.ACTION_REQUEST_SHUTDOWN flg=0x10000000 (has extras) }
"This exception is thrown when a call to Context#startActivity or one of its variants fails because an Activity can not be found to execute the given Intent."
I am assuming that this may require me to modify my manifist.xml, is that correct? If so, I'm unsure how to do so. I feel that I may have to add an to my main activity, where the call is made. Though, I've tried this and it didn't work, or I wrote the code improperly.
Thank you in advance for any assistance!
Figured this one out. I didn't realize a PowerManager existed, but it does, and it works. My solution below. Also, if you didn't read the full question, my app is a privileged/System app, which gives me the authority to manage power. Normal apps will not be able to do this.
Currently running Android 9.0 (might matter, not sure)
try{
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
powerManager.reboot(null);
} catch (Exception e){
Toast.makeText(this, "Error performing this action", Toast.LENGTH_LONG).show();
e.printStackTrace();
}

Turn off device programmatically

I am writing an App that is designed to run on one specific device model (an Android set-top device that runs Amlogic based firmware). I have both root capability and my App is signed with the firmware certificate.
My App is the main focus of the device, and it would be helpful to be able to initiate a complete power-off.
I do not have the shutdown command. I do have the reboot command.
reboot -p does not help. It simply freezes the device while remaining powered on.
The PowerManager is one step better, but it sets the device into sleep mode, instead of a complete shutdown:
PowerManager pm = (PowerManager)getSystemService(Service.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());
I am open to all suggestions - hacky or otherwise. The version of Android is expected to remain at 4.2.2.
Intents
This command will cause the device to reboot. Intent.ACTION_SHUTDOWN does not appear to do anything. Is this Intent perhaps only to report a shutdown, and not to initiate one?
Intent i = new Intent(Intent.ACTION_REBOOT);
i.putExtra("nowait", 1);
i.putExtra("interval", 1);
i.putExtra("window", 0);
sendBroadcast(i);
The most luck I had with this was to request a shutdown by Intent:
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);
Shutdown Thread
That is a bit closer. Definitely interesting. Can you find an example of using it?
So far I have come up with this:
Class<?> sdClass = Class.forName("com.android.server.power.ShutdownThread");
Constructor<?> con = sdClass.getDeclaredConstructors()[0];
con.setAccessible(true);
for (Method m : sdClass.getDeclaredMethods()) {
if (m.getName().matches("shutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("rebootOrShutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("beginShutdownSequence")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
}
}
shutdown and beginShutdownSequence create NullPointerExceptions (do you see why?) and rebootOrShutdown creates an InvocationTargetException due to an UnsatisfiedLinkError... It cannot find a native method:
java.lang.UnsatisfiedLinkError: Native method not found:
com.android.server.power.PowerManagerService.nativeShutdown:()V at
com.android.server.power.PowerManagerService.nativeShutdown(Native
Method) at
com.android.server.power.PowerManagerService.lowLevelShutdown(PowerManagerService.java:2163)
at
com.android.server.power.ShutdownThread.rebootOrShutdown(ShutdownThread.java:543)
at
com.android.server.power.ShutdownThread.run(ShutdownThread.java:393)
lowLevelShutdown is the function that all the functions eventually reach, when configured to shutdown (and not reboot). So figuring out how to avoid this link error may be key.
In my case, I do not think it is possible to shut the device down how I would like to.
The closest that I managed to get to my target was using:
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);
That brings up a dialog to turn the device off. This is the perfect solution, but in my case, using it causes the device to crash. It may be that my device is somewhat special, and other devices will not have these restrictions.
In any case, I hope that my testing will help others in their quest.
It work for me on rooted device.
If your device is rooted then you can use below approach
Shutdown:
try {
Process proc = Runtime.getRuntime()
.exec(new String[]{ "su", "-c", "reboot -p" });
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
Restart:
Same code, just use "reboot" instead of "reboot -p".
Runtime.getRuntime().exec(new String[]{ "su", "-c", "reboot -p" });
it works, just with rooted devices!!
To use this code, you need Super User! Works on 4.0 and above!
Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", false);
i.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
and put this permission on manifest:
<uses-permission android:name="android.permission.SHUTDOWN" />
An update: for newer Android version, in my case is Android 8.1, they changed the action name. See below:
Intent i = new Intent("com.android.internal.intent.action.REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", false);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Good luck!
In newer android versions you aren't allowed to shut down the device from the nonSystem app.

Power off Android device with system signed application

I am developing an Android application and we need to power off the device under certain circumstances.
I have read in many places that you need a rooted phone in order to do so. Then, you can issue the "reboot" command by using Java's API:
try {
Process proc = Runtime.getRuntime()
.exec(new String[]{ "su", "-c", "reboot -p" });
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
I have actually tried this in a Cyanogenmod 10 device (Samsung Galaxy S3), and it works. However, we do not want a rooted device in order to power it off, since the end user will then be able to do unintended things which are not allowed by our company.
On the other hand, our application is signed by the manufacturer's certificate, in this case Cyanogen's. I have read that by signing your application with the manufacturer's certificate, you should be able to issue privileged commands (as if root). However, even if I install my app as a system app signed with the manufacturer's certificate, the above code does not work:
If I leave the "su" part of the command, the "Superuser Request" screen is displayed, but that's something we are trying to avoid.
If I remove the "su" part (just leaving "reboot -p"), the command is silently ignored.
As a result, we are not being able to poweroff our device with our system app, which is signed with the manifacturer's certificate. So my question is, how am I supposed to do that?
EDITED
And, by the way, just in case someone is not sure about it: the application is properly signed and installed as a system application, because we can actually access some restricted APIs, such as PowerManager.goToSleep()
If you want the device to reboot (power off and on), then try PowerManager.reboot()
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
powerManager.reboot(null);
android.os.PowerManager:
/**
* Reboot the device. Will not return if the reboot is successful.
* <p>
* Requires the {#link android.Manifest.permission#REBOOT} permission.
* </p>
*
* #param reason code to pass to the kernel (e.g., "recovery") to
* request special boot modes, or null.
*/
public void reboot(String reason) {
try {
mService.reboot(false, reason, true);
} catch (RemoteException e) {
}
}
UPDATE
If you want the device to completely turn off, use PowerManagerService.shutdown():
IPowerManager powerManager = IPowerManager.Stub.asInterface(
ServiceManager.getService(Context.POWER_SERVICE));
try {
powerManager.shutdown(false, false);
} catch (RemoteException e) {
}
com.android.server.power.PowerManagerService:
/**
* Shuts down the device.
*
* #param confirm If true, shows a shutdown confirmation dialog.
* #param wait If true, this call waits for the shutdown to complete and does not return.
*/
#Override // Binder call
public void shutdown(boolean confirm, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(true, confirm, null, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
This was working fine for me:
startActivity(new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN"));
you need this permission ( depends on being system-app ):
<uses-permission android:name="android.permission.SHUTDOWN"/>
source:
https://github.com/sas101/shutdown-android-app/wiki
OK, my mistake.
As I performed some tests, I did not realize that I had removed "android:sharedUserId="android.uid.system" from the manifest.
Once the sharedUserId is included, the following code works without prompting the user to confirm root access:
try {
Process proc = Runtime.getRuntime()
.exec(new String[]{ "su", "-c", "reboot -p" });
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
I tried to remove "su" (because the system may not provide such a command), but in that case it does not work. Surprisingly, the file system is remounted in read-only mode, so I must remount it again with write permissions.
this is for kotlin
(requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager)
.reboot("reason")

Error setting the CPU scaling governor through app

I'm creating a simple Android app that should set the CPU Scaling Governor.
To achieve this I made this function:
public static void setCurrentGovernor(String governor){
Process process;
try{
String cpufreq_path= "/sys/devices/system/cpu/cpu0/cpufreq";
String cmd = "echo `"+governor+"` > "+cpufreq_path+"/scaling_governor ";
process = Runtime.getRuntime().exec(new String[] {"su","-c",cmd});
} catch(IOException e){
e.printStackTrace();
}
}
My problem is that this function won't work, plus superuser always prompts me for permissions, is there a way to give it root permission only at first app boot?
This function is called inside an onitemselectedlistener of a spinner, right after this function there's another one which fetches data from cpufreq files to update the view, but if i do cat scaling_governor i get the old governor, so it is not a faulty update function.
This more solid code solved my problem:
Link

Android "permanent" superuser permission for an app?

To clarify, I use this code to get superuser permission for my app so I can access root and whatnot:
public String runProcess(String[] functs) {
DataOutputStream dos;
DataInputStream dis;
StringBuffer contents = new StringBuffer("");
String tempInput;
Process process;
try {
process = Runtime.getRuntime().exec(functs);
dos = new DataOutputStream(process.getOutputStream());
dis = new DataInputStream(process.getInputStream());
for (String command : functs) {
dos.writeBytes(command + "\n");
dos.flush();
while ((tempInput = dis.readLine()) != null)
contents.append(tempInput + "\n");
}
dos.writeBytes("exit\n");
dos.flush();
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
return contents.toString();
}
And although it works just fine, whenever I call runProcess(new String[] { "su", "-c", "some other command" }); it always asks for superuser permission. I see a lot of root apps on the market who just have to gain superuser permission once at each startup of the app, but I don't think I'd need to ask the user for superuser permission every single time the app calls an function that requires SU. So my question would be, how would I prompt the user to give me SU permission once at the startup of an app without having to continually ask for it for every SU-related action?
EDIT: I know I could run my method/the Runtime.getRuntime().exec() method without typing "su" in it every time but that only works with non-su related actions (i.e. exec("ps") or exec("ls"). Any ideas?
You can use my Library which does this.
https://code.google.com/p/roottools/
Also, if you don't want to use the library the source is available so you can just rip out my code and use it in your application.
Here is a link to the source:
https://code.google.com/p/roottools/source/browse/#svn%2Ftrunk%2FStable%2FRootTools-sdk3-generic%2Fsrc%2Fcom%2Fstericson%2FRootTools
If you are just looking for the permission from a "superUser" app which is already running in your device, you just need the following code in your main java file.
try {
process p= Runtime.getRuntime().exec(su);
}
catch (IOException e) {
e.printStackTrace();
}
Yes, no need to mention that the device has to be already rooted!!!
Every time you open a console asking for root access, i.e. start it with su, the corresponding super user app will either prompt you or allow/deny it, if you checked something like "Don't ask me again" on the previous prompt.
If you only want to have ask (the super user app) once, you will have to keep your root console open, by not calling dos.writeBytes("exit\n");.
Then keep this session in a background thread and use it when necessary.
So either make sure the user checks "Don't ask me again" on the first prompt or keep the session open.

Categories

Resources