写点什么

Android 实现系统深度休眠笔记

用户头像
Android架构
关注
发布于: 2021 年 11 月 07 日
  • 休眠几个坑点及解决


1.向服务器轮询的代码不执行:曾经做一个应用,利用 Timer 和 TimerTask,来设置对服务器进行定时的轮询,但是发现机器在某段时间后,轮询就不再进行了。查了很久才发现是休眠造成的。后来解决的办法是,利用系统的 AlarmManager 来执行轮询。因为虽然系统让机器休眠,节省电量,但并不是完全的关机,系统有一部分优先级很高的程序还是在执行的,比如闹钟,利用 AlarmManager 可以定时启动自己的程序,让 cpu 启动,执行完毕再休眠(按:如上述,就是通过 BP 唤醒 AP)。


2.后台长连接断开:最近遇到的问题。利用 Socket 长连接实现 QQ 类似的聊天功能,发现在屏幕熄灭一段时间后,Socket 就被断开。屏幕开启的时候需进行重连,但每次看 Log 的时候又发现网络是链接的,后来才发现是 cpu 休眠导致链接被断开,当你插上数据线看 log 的时候,网络 cpu 恢复,一看网络确实是链接的, 坑。最后使用了 PARTIAL_WAKE_LOCK,保持 CPU 不休眠。


3.调试时是不会休眠的:在调试 2 的时候,就发现,有时 Socket 会断开,有时不会断开,后来才搞明白,因为我有时是插着数据线进行调试,有时拔掉数据线,这时 Android 的休眠状态是不一样的。而且不同的机器也有不同的表现,比如有的机器,插着数据线就会充电,有的不会,有的机器的设置的充电时屏幕不变暗等等。


  • DC 连接汽车 12V 永不掉电,熄火时 ACC 发出掉电信号时,行车记录装置采用不关机,深度休眠策略。关闭屏幕,停止录像,记录轨迹的同时,需要打开飞行模式(蓝牙,WiFi),关闭 FM 发射,关闭 GPS。如果此时有音乐播放和后台导航,也需要关闭。

  • 深度休眠时,待机电流降到 10-30mA,此时底层摄像头已不再断电,所以在此步骤进行之前,要停掉 Camera 预览。否则机器唤醒的时候预览区域会出现卡死。

  • 关闭屏幕,发送自定义广播:


context.sendBroadcast(new Intent("tchip.intent.action.ACTION_KEY_POWER"));


接收的应用,需要具备 INJECT_EVENTS 权限:


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


和系统的 userId:


android:sharedUserId="android.uid.system"


接收到此广播后,发出对应的 key 即可:


sendKeyCode(KeyEvent.KEYCODE_POWER);


  • 打开/关闭飞行模式,同样发送自定义广播给拥有系统 uid 的应用,同时需要具备权限写入 WRITE_SECURE_SETTINGS,打开 setting.db 可以看到三个表,其中 secure 表是一些敏感字段:




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


然后执行对应的操作:


/**


  • 当前是否开启飞行模式


*/


private boolean isAirplaneModeOn(Context context) {


// 返回值是 1 时表示处于飞行模式


int modeIdx = Settings.Global.getInt(context.getContentResolver(),


Settings.Global.AIRPLANE_MODE_ON, 0);


boolean isEnabled = (modeIdx == 1);


//MyLog.v("[SleepReceiver]isAirplaneModeOn:" + isEnabled);


return isEnabled;


}


/**


  • 设置飞行模式


*/


private void setAirplaneMode(boolean setAirPlane, Context context) { Settings.Global.putInt(context.getContentResolver(),


Settings.Global.AIRPLANE_MODE_ON, setAirPlane ? 1 : 0);


// 广播飞行模式的改变,让相应的程序可以处理。


Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);


intent.putExtra("state", setAirPlane);


context.sendBroadcast(intent);


}


  • 根据包名杀死后台应用:


public void killAppByPackageName(String package){


ActivityManager myActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);


List<ActivityManager.RunningAppProcessInfo> mRunningPros = myActivityManager.getRunningAppProcesses();


for (ActivityManager.RunningAppProcessInfo amPro : mRunningPros){


if(amPro.processName.contains(package)){


try {


Method forceStopPackage = myActivityManager.getClass().getDeclaredMethod("forceStopPackage", String.class);


forceStopPackage.setAccessible(true);


forceStopPackage.invoke(myActivityManager, amPro.processName);


}


catch (Exception e) {


}


}


}


  • 媒体/铃声声音静音,需要保存休眠前的音量,供唤醒后恢复:


if (Constant.Module.muteWhenSleep) {


int volumeMusic = audioManager .getStreamMaxVolume(AudioManager.STREAM_MUSIC);


int volumeRing = audioManager .getStreamVolume(AudioManager.STREAM_RING);


editor.putInt("volumeMusic", volumeMusic);


editor.putInt("volumeRing", volumeRing);


editor.commit();


}


  • 关闭/打开 GPS


context.sendBroadcast(new Intent(


"tchip.intent.action.ACTION_GPS_OFF"));


private static boolean getGpsState(Context context) {


ContentResolver resolver = context.getContentResolver();


boolean gpsState = Settings.Secure.isLocationProviderEnabled(resolver,


LocationManager.GPS_PROVIDER);


Log.v("ZMS", "[GPS]Now State:" + gpsState);


return gpsState;


}


private void setGpsState(Context context, boolean isGpsOn) {


ContentResolver resolver = context.getContentResolver();


boolean nowState = getGpsState(context);


if (isGpsOn != nowState) {


Log.v("ZMS", "[GPS]Set State:" + isGpsOn);


Settings.Secure.setLocationProviderEnabled(resolver,


LocationManager.GPS_PROVIDER, isGpsOn);


}


}


  • 停止录像预览,释放 recorder:由于熄屏时,不会触发 SurfaceView 的 surfaceDestroy,所以将 destroy 的过程移动到 Activity 的 onPause 中执行


private void releaseCameraZone() {


release();


// mHolder = null;


if (mCamera != null) {


mCamera.stopPreview();


}


MyApplication.shouldResetRecordWhenResume = true;


}


public void release() {


releaseRecorder();


closeCamera();


}


private void releaseRecorder() {


if (mMyRecorder != null) {


mMyRecorder.stop();


mMyRecorder.close();


mMyRecorder.release();


mMyRecorder = null;


MyLog.d("Record Release");


}


}


private boolean closeCamera() {


if (mCamera == null)


return true;


try {


mCa


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


mera.lock();


mCamera.stopPreview();


mCamera.setPreviewDisplay(null);


mCamera.release();


mCamera.unlock();


mCamera = null;


return true;


} catch (Exception ex) {


mCamera = null;


return false;


}


}






唤醒


--


  • 摄像头预览区域重新绘制,在 Activity 的 onResume 中判断是否需要执行:


if (!MyApplication.isFirstLaunch) {


if (!MyApplication.isVideoReording


|| MyApplication.shouldResetRecordWhenResume) {

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android 实现系统深度休眠笔记