客户反馈问题:目前最大问题是,断电机器没有休眠 是一直在工作,只是关了显示屏,
1, 断电之后(这个断电是指usb线拔插) 本身喇叭和AUX音频输出没有关闭。
安卓休眠流程这里就不介绍了
安卓休眠流程
测试发现,调用第三方播放音频时会,调用休眠方法,并不能休眠下去,本身喇叭和AUX音频确实还有输出
powerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
通过命令发现播放媒体时会添加对应的锁 dumpsys power
Wake Locks: size=3
FULL_WAKE_LOCK 'bright' ACQUIRE_CAUSES_WAKEUP ON_AFTER_RELEASE ACQ=-2m4s832ms (uid=10090 pid=3171)
PARTIAL_WAKE_LOCK 'AudioMix' ACQ=-1s466ms (uid=1041 ws=WorkSource{10106})
PARTIAL_WAKE_LOCK 'APlayer' ACQ=-1s878ms (uid=10106 pid=6306)
\frameworks\av\services\audioflinger\Threads.cpp
String16 AudioFlinger::ThreadBase::getWakeLockTag()
{
switch (mType) {
case MIXER:
return String16("AudioMix");
case DIRECT:
return String16("AudioDirectOut");
case DUPLICATING:
return String16("AudioDup");
case RECORD:
return String16("AudioIn");
case OFFLOAD:
return String16("AudioOffload");
case MMAP:
return String16("Mmap");
default:
ALOG_ASSERT(false);
return String16("AudioUnknown");
}
}
首先尝试释对应的放锁,似乎并没有影响,对应的媒体并没有暂停播放;
Index: services/core/java/com/android/server/power/PowerManagerService.java
===================================================================
@VisibleForTesting
final class BatteryReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (mLock) {
handleBatteryStateChangedLocked();
//removeWakeLock
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 0);
boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL);
if (!isCharging){//释放锁
final int count = mWakeLocks.size();
for (int i = count-1; i >=0; i--) {
WakeLock wakeLock = mWakeLocks.get(i);
wakeLock.mLock.unlinkToDeath(wakeLock, 0);
removeWakeLockLocked(wakeLock, i);
}
mBinderService.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
}
}
}
}
那么想到的就三种处理方式:
第一种就是app端配合,调用休眠前先结束媒体播放;
第二种就比较简单粗暴了:就是kill掉其他应用,唤醒后再拉起应用;
Index: data/etc/com.android.systemui.xml
===================================================================
<permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <permission name="android.permission.FORCE_STOP_PACKAGES"/>
</privapp-permissions>
Index: packages/SystemUI/AndroidManifest.xml
===================================================================
@@ -238,6 +238,9 @@
<!-- Permission to control Android Debug Bridge (ADB) -->
<uses-permission android:name="android.permission.MANAGE_DEBUGGING" />
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
+
+
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
<!-- Permission to change the display color -->
Index: packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
===================================================================
@@ -109,6 +109,19 @@
import com.android.systemui.statusbar.CommandQueue;
import android.os.BatteryManager;
import android.os.SystemProperties;
+import android.widget.Toast;
+import android.os.PowerManager;
+import android.app.Instrumentation;
+import android.view.KeyEvent;
+import com.android.internal.statusbar.IStatusBarService;
+import android.os.ServiceManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.content.ComponentName;
+import android.os.Build;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
/**
* Application class for SystemUI.
@@ -134,6 +147,7 @@
private HandlerThread mKeyboxThread = new HandlerThread("keybox");
private Handler mKeyboxHandler;
private static final int MSG_CHECK_KEYBOX = 1;
+ private static final int MSG_LOCK_USB_STATE = 11;
private int mRetryCount = 2;
public static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
@@ -284,9 +298,16 @@
}
return myName;
}
+ private PowerManager.WakeLock wakeLock;
+ private boolean wakeLockRelease=false;
+ private IStatusBarService mBarService;
+ PowerManager powerManager;
+ private Context mContext;
+
@Override
public void onCreate() {
super.onCreate();
+ mContext = this;
// Set the application theme that is inherited by all services. Note that setting the
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
@@ -313,7 +334,8 @@
mBaseStartServices.add("com.android.systemui.recents.Recents");
mBaseStartServices.add("com.android.systemui.globalactions.GlobalActionsComponent");
}
-
+ initLock();
+ powerManager= (PowerManager)getSystemService(Context.POWER_SERVICE);
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
bootCompletedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -360,6 +382,7 @@
}, bootCompletedFilter);
IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
+ localeChangedFilter.addAction("android.hardware.usb.action.USB_STATE");//监听usb状态
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -367,6 +390,22 @@
if (!mBootCompleted) return;
// Update names of SystemUi notification channels
NotificationChannels.createAll(context);
+ }else if ("android.hardware.usb.action.USB_STATE".equals(intent.getAction())){
+ Message msg;
+ if (mKeyboxHandler !=null) {
+ msg = mKeyboxHandler.obtainMessage();
+ msg.what= MSG_LOCK_USB_STATE;
+ if (intent.getExtras().getBoolean("connected")){
+ msg.obj= 1;
+ // usb 插入
+ // Toast.makeText(context, "插入", Toast.LENGTH_LONG).show();
+ }else{
+ msg.obj= 0;
+ // usb 拔出
+ // Toast.makeText(context, "拔出", Toast.LENGTH_LONG).show();
+ }
+ mKeyboxHandler.sendMessage(msg);
+ }
}
}
}, localeChangedFilter);
@@ -539,6 +578,13 @@
}
}
}
+ }else if(msg.what == MSG_LOCK_USB_STATE){
+ int obj= (int)msg.obj;
+ if (obj==1) {
+ lockAcquire();
+ }else{
+ releaseLock();
+ }
}
}
};
@@ -547,13 +593,130 @@
Log.d(TAG,"onReceive action="+intent.getAction());
mHasBattery = (hasBattery(intent) || sysCheckBattery());
Settings.System.putInt(context.getContentResolver(), "check_battery", mHasBattery?1:0);
+ if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+ Message msg;
+ if (mKeyboxHandler !=null) {
+ msg = mKeyboxHandler.obtainMessage();
+ msg.what= MSG_LOCK_USB_STATE;
+ int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 0);
+ boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL);
+ if (isCharging){
+ msg.obj= 1;
+ }else{
+ msg.obj= 0;
+ }
+ mKeyboxHandler.sendMessage(msg);
+ }
+ }
}
},new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
- mHasBattery = (hasBattery(batteryBroadcast)||sysCheckBattery());
+ mHasBattery = (hasBattery(batteryBroadcast)||sysCheckBattery());
Settings.System.putInt(getContentResolver(), "check_battery", mHasBattery?1:0);
}
+/**
+ *
+ * PARTIAL_WAKE_LOCK: 保持CPU 运转,屏幕和键盘灯可以关闭。
+ * SCREEN_DIM_WAKE_LOCK: 保持CPU 运转,保持屏幕显示,但可以变暗,允许键盘灯关闭。
+ * SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许键盘灯关闭。
+ * FULL_WAKE_LOCK: 保持CPU 运转,保持屏幕和键盘灯都高亮显示。
+ * ACQUIRE_CAUSES_WAKEUP: 当获取锁后,立刻亮屏,典型地使用在通知中,以让用户立刻查看。
+ * ON_AFTER_RELEASE: 在释放锁(release())后,手机屏幕仍会继续亮一会儿。
+ *
+ */
+ private void initLock(){
+ if (wakeLock==null) {
+ wakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "bright");
+ wakeLockRelease=false;
+ Log.e(TAG,"wakeLock initLock");
+ }
+ }
+ private void lockAcquire(){
+ if (wakeLock!=null && !wakeLockRelease) {
+ wakeLock.acquire();
+ Log.e(TAG,"wakeLock acquire");
+ wakeLockRelease=true;
+ Log.e(TAG,"lockAcquire mCn=" + mCn);
+ if (mCn !=null) {
+ Intent intent=new Intent();
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(mCn);
+ startActivity(intent);
+ }
+ //Toast.makeText(mContext, "wakeLock acquire", Toast.LENGTH_LONG).show();
+ }
+ }
+
+ private void releaseLock(){
+ if (wakeLock!=null && wakeLockRelease) {
+ wakeLock.release();
+ Log.e(TAG,"wakeLock release");
+ //Toast.makeText(mContext, "wakeLock release", Toast.LENGTH_LONG).show();
+ wakeLockRelease=false;
+ if(true){ //方式1,暂停媒体,不确定应用那边是否有做,待验证,最好是驱动那边是否看下是否能强制休眠
+ //onKeyEvent(KeyEvent.KEYCODE_MEDIA_PAUSE);
+ killBackgroundProcesses();
+ powerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ }else{ //方式二kill掉其他应用
+ killBackgroundProcesses();
+ powerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
+ }
+ }
+ }
+ ComponentName mCn = null;
+
+ public void killBackgroundProcesses() {
+ try {
+ ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ List<ActivityManager.RunningTaskInfo> runningTaskInfos = manager.getRunningTasks(100);
+ mCn=null;
+ for (int i = 0; i < runningTaskInfos.size(); i++) {
+ ComponentName cn = null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ cn = runningTaskInfos.get(i).topActivity;
+ }
+ String pkg = cn.getPackageName();
+ Log.e(TAG,"pkg=" + pkg);
+ //kill掉指定应用
+ if (pkg.contains("com.tencent.qqmusiccar")){
+ try {
+ Method forceStopPackage = manager.getClass().getDeclaredMethod("forceStopPackage", String.class);
+ forceStopPackage.setAccessible(true);
+ forceStopPackage.invoke(manager, pkg);
+ Log.e(TAG,"invoke pkg=" + pkg);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ if (i==0) {
+ mCn=cn;
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * @hide 模拟系统按键。
+ */
+ public void onKeyEvent(final int keyCode) {
+ new Thread() {
+ public void run() {
+ try {
+ Instrumentation inst = new Instrumentation();
+ inst.sendKeyDownUpSync(keyCode);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }.start();
+ }
第三种方式:通过AudioManager 去抢占媒体焦点,把第三方应用的媒体播放挤掉,直到用户点击再次获取焦点
AudioManager am = (AudioManager) getSystemService (Context.AUDIO_SERVICE);
am.requestAudioFocus(focusChange -> Log.e(TAG,"OnAudioFocusChangeListener focusChange="+focusChange), AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
网友评论