Several implementation methods of Android system shutdown or restart

The default SDK does not provide an API interface for application developers to directly shut down or restart the Android system. Generally speaking, high permissions (system permissions or even Root permissions) are required to shut down or restart the Android system. Therefore, in general apps, if you want to realize the shutdown or restart function, you can either declare the system permission in the app, or indirectly realize the system shutdown or restart through some "indirect" way, such as broadcast or reflection. In addition, it is compiled in the source environment. One advantage of this is that it can directly call the non-public API in Android, which is an effect that Eclipse + SDK cannot achieve. Here are some ways I try:

I Broadcast mode of transmission system

Broadcast is one of the four basic components of Android, which is what we often call broadcast. The Android system itself contains many broadcasts. It monitors every broadcast registered in the system all the time and is ready to respond to operations at any time. Among them, there is a broadcast about shutdown or restart: intent ACTION_REQUEST_ Shutdown and intent ACTION_REBOOT: by sending these two broadcasts, Android can automatically receive the broadcasts and respond to the operation of shutdown or restart. ACTION_REQUEST and ACTION_REBOOT is intent Java is the declared two string constants

   public static final String ACTION_REBOOT =
              "android.intent.action.REBOOT";
   public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";

Intent.java is located in the source code / frameworks / base / core / Java / Android / content / intent Java. The specific implementation method is as follows
//Broadcast mode shutdown and restart

case R.id.shutdown_btn1:
    Log.v(TAG, "broadcast->shutdown");
    Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
    intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
    //If false is changed to true, a confirmation window will pop up to confirm whether to shut down
    startActivity(intent);
break;
case R.id.reboot_btn1:
    Log.v(TAG, "broadcast->reboot");
    Intent intent2 = new Intent(Intent.ACTION_REBOOT);
    intent2.putExtra("nowait", 1);
    intent2.putExtra("interval", 1);
    intent2.putExtra("window", 0);
    sendBroadcast(intent2);  
    break;


The following points need to be noted:

First, as mentioned earlier, the APP needs to be upgraded to the system permission. The specific method is in androidmenifest Add the following code to XML

android:sharedUserId="android.uid.system"

Second, you need to add shutdown permission at the same time

<uses-permission android:name="android.permission.SHUTDOWN" />

Third, in Eclipse, the code for intent ACTION_ REQUEST_ Shutdown and intent EXTRA_ KEY_ Confirm reports an error in the Eclipse IDE. As mentioned above, these two attributes are not open to the upper layer. If the project is compiled in the source code, it can be compiled.
Fourth, because you need to compile the project in the source code, you need to write mk files for the project and add android.com in the root directory of the project mk file, as follows:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := PowerActionDemo
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE) 


Finally, you can verify the function by pushing the compiled apk file to the machine through ADB.

II Through init RC starts the system service to run the sh file

After Android starts the file system, the first application that will be called is /init. This document is a very important content that parses init.. RC and init xxx. RC, and then execute the parsed task. And init RC, you can perform some simple initialization operations in the initialization process of the system. Using this, you can write a simple shutdown or restart sh script file, and perform the corresponding shutdown or restart operation through system init analysis.

1. First, write the sh script for shutdown and restart. For example, new

Restart script system_reboot.sh, as follows:

#!/system/bin/sh  
reboot
 shutdown script  system_shutdown.sh
#!/system/bin/sh  
reboot -p

Note: the shutdown command here is not shutdown, but reboot -p (if there is a shutdown file in the system/bin directory of your android system, you can also use the shutdown command, because my system only reboots, so reboot -p is used instead of shutdown)
2. Write Android MK compilation script is to compile the two sh files together into the / system/bin directory when compiling the source code

LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
LOCAL_PREBUILT_EXECUTABLES := system_shutdown.sh system_reboot.sh
LOCAL_MODULE_TAGS := optional
include $(BUILD_MULTI_PREBUILT)

3. init.rc add shutdown and restart services and open init RC file, add the following content on the last side:

service system_shutdown /system/bin/system_shutdown.sh
        oneshot
        disabled 
 
service system_reboot /system/bin/system_reboot.sh
        oneshot
        disabled

The oneshot option means that the service is started only once. Without the oneshot option, the executable will always exist -- if the executable is killed, it will be restarted.
Disabled indicates that the service is disabled. This service will not start automatically when it is turned on, but it can be started manually in the application.

4. Create a new directory, such as poweraction, and add the above Android mk , system_ shutdown. sh, system_ reboot. Put SH in this directory, and then copy the directory of poweraction to the Android system, such as under the device path. Then, compile the Android source code. After compiling the source code, view the generated out // Does system / bin contain system_shutdown.sh, system_reboot.sh two sh files. If there are, the compilation is successful.

5. Finally, start the system service to shut down or restart.


//Start system services for shutdown or restart

case R.id.shutdown_btn2:
    Log.v(TAG, "system service->shutdown");
    SystemProperties.set("ctl.start", "system_shutdwon");
    break;
case R.id.reboot_btn2:
    Log.v(TAG, "system service->reboot");
    SystemProperties.set("ctl.start", "system_reboot");
    break;


III Runtime calls Linux shell

We know that the Java class Runtime can be used to call and execute shell commands, while the Android virtual machine supports Linux shell language. Based on this, the Runtime can be used to execute shell commands for shutdown or restart, which is roughly the same as the principle of mode 2 described above. The function codes are as follows:

//Runtime execution linux shell
case R.id.shutdown_btn3:
    try{
        Log.v(TAG, "root Runtime->shutdown");
        //Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","shutdown"});  / / shutdown
        Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","reboot -p"});  //Shut down
        proc.waitFor();
    }catch(Exception e){
        e.printStackTrace();
    }
    break;
case R.id.reboot_btn3:
    try { 
        Log.v(TAG, "root Runtime->reboot");
        Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","reboot "});  //Shut down
        proc.waitFor();
    }catch (Exception ex){
        ex.printStackTrace();
    }
    break; 

Using this method, it should be noted that ordinary users do not have permission to perform reboot and shutdown, and naturally they cannot shut down or restart. The Android device used must have been root. The above code plus the su command is actually to obtain administrator privileges. In addition, it should be noted that the premise that this method can work is that there are reboot and shutdown files in the system/bin directory of your Android system (in fact, it is the same as the above principle, which also calls the files in the bin directory). It is said that most devices have reboot and shutdown files, but the RK Android system I use does not have shutdown files, so, Cannot be used directly

Runtime.getRuntime().exec(new String[]{"su","-c","shutdown"})

You can only execute the following command to shut down (what a magical p parameter)

Runtime.getRuntime().exec(new String[]{"su","-c","reboot -p"});

IV PowerManager reboot and reflection call PowerManagerService shutdown
1. PowerManager provides reboot and other interfaces. Therefore, it is relatively simple to use PowerManager to restart.

PowerManager pManager=(PowerManager) getSystemService(Context.POWER_SERVICE);  
pManager.reboot(null);//restart

2. PowerManager class does not provide shutdown interface for shutdown, but communicates with PowerManagerService class through IBinder, a unique communication mode in Android. PowerManagerService is the concrete implementation of the interface defined in PowerManager class, and further calls power class to communicate with the next layer The PowerManagerService implements the shutdown interface, and the power service implements the shutdown function
The implementation of PowerManager calls the interface of Power service through IPowerManager. IPowerManager is a class automatically generated by AIDL files, which is convenient for remote communication. IPowerManage.aidl file directory
framework/base/core/java/android/os/IPowerManage.aidl 

IPowerManager implements the shutdown interface, so if we can get the IBinder of Power service, we can call the shutdown method through reflection to realize the shutdown function.
It should be noted that the ServiceManager manages the service program of the system. It saves the IBinder of all services. The IBinder of this service can be obtained through the service name.
However, the ServiceManager class is also HIDE and needs to be called by reflection. Twice, through two reflection calls, the shutdown function realized by power service can be called.

 try {
 
     //Get ServiceManager class
     Class<?> ServiceManager = Class.forName("android.os.ServiceManager");
     
     //Get the getService method of ServiceManager
     Method getService = ServiceManager.getMethod("getService", java.lang.String.class);
     
     //Call getService to get RemoteService
     Object oRemoteService = getService.invoke(null,Context.POWER_SERVICE);
     
     //Obtain ipowermanager Stub class
     Class<?> cStub = Class.forName("android.os.IPowerManager$Stub");
     //Get asInterface method
     Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class);
     //Call the asInterface method to get the IPowerManager object
     Object oIPowerManager = asInterface.invoke(null, oRemoteService);
     //Get shutdown() method
     Method shutdown = oIPowerManager.getClass().getMethod("shutdown",boolean.class,boolean.class);
     //Call the shutdown() method
     shutdown.invoke(oIPowerManager,false,true);           
 
   } catch (Exception e) {         
       Log.e(TAG, e.toString(), e);        
   }


5, Use shutdown thread (the attempt is unsuccessful, but the idea feels feasible)

In fact, when PowerManager is used to shut down or restart, PowerManager will continue or call the relevant interface of shuttwinthread. such as

Reboot interface provided by PowerManager. In PowerManager, the implementation code of reboot() is as follows:

 public void reboot(String reason) {
        try {
            mService.reboot(false, reason, true);
        } catch (RemoteException e) {
        }
  }

mService is of IPowerManager type. As we said earlier, PowerManagerService is the specific implementation of PowerManager, and the interface for PowerManager to call PowerManagerService is the interface for PowerManager to call Power service through IPowerManager. Therefore, if you continue to track the code in PowerManagerService, you can know that there is the implementation of reboot ().

@Override // Binder call
    public void reboot(boolean confirm, String reason, boolean wait) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
 
        final long ident = Binder.clearCallingIdentity();
        try {
            shutdownOrRebootInternal(false, confirm, reason, wait);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
  }

Continue to track shutdown or reboot internal (false, confirm, reason, wait);

  

private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
              final String reason, boolean wait) {
          if (mHandler == null || !mSystemReady) {
              throw new IllegalStateException("Too early to call shutdown() or reboot()");
          }
  
          Runnable runnable = new Runnable() {
              @Override
              public void run() {
                  synchronized (this) {
                      if (shutdown) {
                          ShutdownThread.shutdown(mContext, confirm);
                      } else {
                          ShutdownThread.reboot(mContext, reason, confirm);
                      }
                  }
              }
          };

We will know that it finally calls ShutdownThread reboot() in Java. From the above code, we also know that the shutdown thread also provides a shutdown interface.


Therefore, if you can use shutdown thread, everything will be much more convenient

However, Shutdown does not provide a public API. Some people on the Internet say that you can, directly

Import com.android.server.pm.ShutdownThread

Execute through. Shutdown Shutdown () or shutdown Reboot(), you can shut down or restart accordingly.

However, I put it in the source code environment and found that it failed to compile. I didn't delve into the specific reasons. I'll continue to see it when I have time next time. However, I think this approach is also possible. Maybe I missed something, which led to the failure of compilation.
 

Keywords: Android

Added by leon_zilber on Sat, 12 Feb 2022 11:11:57 +0200