Android進入suspend狀態(goToSleep)

Android有個很有趣的現象,公開的API把系統進入suspend的功能移除了,開發者想讓Android機器進入suspend狀態,必須使用reflect機制(這種感覺,極爲類似N多年前有一本書專門介紹Windows未公開的API )。

不明白Google爲什麼這麼做,唯一的猜測,是爲了安全考慮。但是,對於某些應用場景,還是需要程序控制Suspend/resume的。

下面簡單介紹其使用,

1. 如果需要使用suspend/resume功能,需要在AndroidManifest.xml聲明獲得“DEVICE_POWER”權限和系統權限,示例代碼如下,

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testsuspend"
    android:sharedUserId="android.uid.system">

    <application
        ...
    </application>

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

</manifest>

 2. 僅僅聲明權限是不夠的,要想擁有system權限,還需要sign,每一款產品的sign key都不一樣,這就造成,即使可以在某一款產品上運行,在其他產品上也是無法運行的(需要使用該產品的sign key重新sign)。

另外,還有一種方法,直接把apk push到文件夾“/system/priv-app/”下,這種方法我沒有嘗試,我一般使用sign key的方式。

adb remount
adb push  xxx.apk  /system/priv-app/
adb reboot 

3. 下面是代碼實現部分,僅供參考,

進入suspend/sleep的代碼段如下,

public static void goToSleep(Context context) {
        PowerManager powerManager= (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        try {
            powerManager.getClass().getMethod("goToSleep", new Class[]{long.class}).invoke(powerManager, SystemClock.uptimeMillis());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
}

屏幕喚醒的代碼段如下,

    public static void wakeUp(Context context) {
        PowerManager powerManager= (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        try {
            powerManager.getClass().getMethod("wakeUp", new Class[]{long.class}).invoke(powerManager, SystemClock.uptimeMillis());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

4. 如果不使用上面的reflect方法,還有沒有其他方法?

據我所查,還有一種不是特別好的方法,即降低SDK版本到20以下,需要做如下更改,

4.1 build.gradle中請指定SDK版本爲20以下,參考如下代碼,注意“compileSdkVersion”已經更改爲20,

apply plugin: 'com.android.application'

android {
    compileSdkVersion 20
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.example.suspendresume"
        minSdkVersion 14
        targetSdkVersion 17
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
    
}

4.2 請在AndroidManifest.xml聲明獲得“DEVICE_POWER”權限和系統權限, 安裝apk前需要sign。

4.3 不使用reflect方式的參考代碼如下,

	private static void enterSuspend(Context context){
        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        pm.goToSleep(SystemClock.uptimeMillis());
	}

5. 如果有該平臺的BSP代碼,也可以把自己的代碼放到BSP中編譯,然後直接包進system image,會省去reflect和sign的動作,不過debug稍微麻煩。

好了,關於奇怪的goToSleep就分享這麼多,希望能爲有需要的童鞋提供幫助。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章