Android系統關機或重啟的幾種實現方式

來源:互聯網
上載者:User

Android系統關機或重啟的幾種實現方式

前陣子工作上遇到一些關於Android系統關機或重啟的系統修改,於是,做了一些嘗試,也搜集了一下資料,現在整理一下,做一些總結,方便學習或者日後工作的需要。

預設的SDK並沒有提供應用開發人員直接的Android系統關機或重啟的API介面,一般來講,實現Android系統的關機或重啟,需要較高的許可權(系統許可權甚至Root許可權)。所以,在一般的APP中,如果想要實現關機或重啟功能,要麼是在App中聲明系統許可權,要麼是通過某種“間接”的方式,比如廣播或反射,來間接實現系統關機或重啟。再者,就是放在源碼環境中進行編譯,這樣做有一個好處,就是可以直接調用Android中不公開的API,這是Eclipse+SDK沒法達到的效果。下面是我自己嘗試的幾種方式:

一. 發送廣播方式

Broadcast是Android的四大基本組件之一,也就是我們常說的廣播。Android系統本身就包含了許多廣播,時時刻刻在監聽著系統中註冊的每一個廣播並隨時準備響應操作。其中,就有關於關機或重啟的廣播:Intent.ACTION_REQUEST_SHUTDOWN和Intent.ACTION_REBOOT,通過發送這兩個廣播,Android就能自動接收廣播,並響應關機或重啟的操作。ACTION_REQUEST和ACTION_REBOOT是Intent.java是聲明的兩個字串常量

   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位於源碼/frameworks/base/core/java/android/content/Intent.java下面。具體實現方法如下

//廣播方式關機重啟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);                //其中false換成true,會彈出是否關機的確認視窗                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                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;

需要注意的幾點是:

第一,如前面所說,需要將APP提升至系統許可權,具體做法是在AndroidMenifest.xml中添加如下代碼

android:sharedUserId="android.uid.system"

第二,同時需要添加關機許可權



第三,在Eclipse中,代碼中的Intent.ACTION_REQUEST_SHUTDOWN 及 Intent.EXTRA_KEY_CONFIRM 在Eclipse IDE中報錯,還是和前面說的一樣,這兩個屬性不對上層開放,如果把項目放在源碼中進行編譯,是可以編譯通過的。

第四,由於需要在源碼中編譯項目,所以需要為項目編寫mk檔案,在項目根目錄下添加Android.mk檔案,內容如下所示:

LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-java-files-under, src)LOCAL_PACKAGE_NAME := PowerActionDemoLOCAL_CERTIFICATE := platforminclude $(BUILD_PACKAGE) 
最後,將編譯產生的apk檔案,通過adb push到機器上就可以驗證功能了。


二. 通過init.rc啟動系統服務來運行sh檔案

Android開機檔案系統後調用的會調用第一個應用程式是/init,此檔案一個很重要的內容就是解析了init.rc和init.xxx.rc,然後執行解析出來的任務。而init.rc,可以在系統的初始化過程中進行一些簡單的初始化操作。利用這一點,可以編寫簡單的關機或重啟的sh指令檔,通過系統init解析,執行相應的關機或重啟操作。

1.首先,編寫關機和重啟的sh指令碼。比如,建立

重啟指令碼 system_reboot.sh,內容如下:

#!/system/bin/sh  reboot
關機指令碼 system_shutdown.sh

#!/system/bin/sh  reboot -p

注意:此處關機命令並不是shutdown,而是reboot -p

2. 編寫Android.mk編譯指令碼,目的是在源碼編譯的時候,將這兩個sh檔案一起編譯到/system/bin目錄下

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

3. init.rc添加關機和重啟的服務,開啟init.rc檔案,在最後面添加如下內容:

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

oneshot選項表示該服務只啟動一次,而如果沒有oneshot選項,這個可執行程式會一直存在--如果可執行程式被殺死,則會重新啟動。

disabled 表示禁用服務,此服務開機時不會自動啟動,但是可以在應用程式中手動啟動它。


4.建立一個目錄,比如poweraction, 將以上的Android.mk , system_shutdown.sh, system_reboot.sh放在這個目錄下,然後將poweraction這個目錄拷貝到Android系統中,比如device路徑下面。然後,編譯Android源碼,源碼編譯完成後, 查看產生的out/.../system/bin下面是不是包含system_shutdown.sh, system_reboot.sh兩個sh檔案,如果有,則說明編譯成功。

5.最後,啟動系統服務,進行關機或重啟。

//啟動系統服務進行關機或重啟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; 

三. Runtime調用Linux-shell

我們知道,Runtime這個Java類是可以用來調用並執行shell命令的,而Android虛擬機器是支援Linux-shell語言的,基於這一點,可以利用Runtime來執行 關機或重啟的shell命令,這一點和上面介紹的方式二原理上大致相同。功能代碼如下:

//Runtime執行linux-shellcase R.id.shutdown_btn3:try{Log.v(TAG, "root Runtime->shutdown");//Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","shutdown"});  //關機Process proc =Runtime.getRuntime().exec(new String[]{"su","-c","reboot -p"});  //關機    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 "});  //關機    proc.waitFor();}catch (Exception ex){ex.printStackTrace();}break; 

使用該方法需要注意的是,普通使用者是沒有許可權執行reboot和shutdown的,自然而然也無法實現關機或重啟。使用的Android裝置必須已經root過,上面的代碼加上su命令其實也就是為了擷取管理員權限。另外一點,需要注意的是,該方法能夠奏效的前提是,你的android系統system/bin 目錄下存在reboot和shutdown檔案(其實跟上面的原理一樣,也是調用bin目錄下的檔案),聽說大部分裝置存在reboot和shutdown這兩個檔案,可使用的Android系統偏偏沒有shutdown檔案,所以,無法直接使用

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

只能執行下面命令來進行關機(好神奇的p參數)

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

四 . PowerManager reboot以及反射調用PowerManagerService shutdown

1. PowerManager提供了reboot等介面,因此,利用PowerManager實現重啟,就比較簡單。

PowerManager pManager=(PowerManager) getSystemService(Context.POWER_SERVICE);  //重啟到fastboot模式pManager.reboot(""); 

2. PowerManager類並沒有提供關機的shutdown介面,而是通過IBinder這種Android中特有的通訊模式,與PowerManagerService 類進行通訊。PowerManagerService是PowerManager 類中定義的介面的具體實現,並進一步調用Power 類來與下一層進行通訊. 在PowerManagerService實現了shutdown介面,power服務實現了關機功能
PowerManager的實現通過IPowerManager來調用Power服務的介面。 IPowerManager是AIDL檔案自動產生的類,便於遠程通訊。IPowerManage.aidl檔案目錄

framework/base/core/java/android/os/IPowerManage.aidl 

IPowerManager實現了shutdown介面,所以,如果我們能夠獲得Power服務的IBinder,通過反射調用shutdown方法就能實現關機功能。
需要注意的是,ServiceManager管理著系統的服務程式,它儲存著所有服務的IBinder,通過服務名就能擷取到這個服務的IBinder。
但ServiceManager這個類也是HIDE的,也需要反射進行調用。兩次,通過兩次反射調用,就能調用power服務實現的關機功能。

 try {                                  //獲得ServiceManager類                 Class ServiceManager = Class                    .forName("android.os.ServiceManager");                                  //獲得ServiceManager的getService方法                 Method getService = ServiceManager.getMethod("getService", java.lang.String.class);                                  //調用getService擷取RemoteService                 Object oRemoteService = getService.invoke(null,Context.POWER_SERVICE);                                  //獲得IPowerManager.Stub類                 Class cStub = Class                    .forName("android.os.IPowerManager$Stub");                 //獲得asInterface方法                 Method asInterface = cStub.getMethod("asInterface", android.os.IBinder.class);                 //調用asInterface方法擷取IPowerManager對象                 Object oIPowerManager = asInterface.invoke(null, oRemoteService);                 //獲得shutdown()方法                 Method shutdown = oIPowerManager.getClass().getMethod("shutdown",boolean.class,boolean.class);                 //調用shutdown()方法                 shutdown.invoke(oIPowerManager,false,true);                             } catch (Exception e) {                     Log.e(TAG, e.toString(), e);               }







聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.