美文网首页
Android 断电休眠(指usb线拔插)

Android 断电休眠(指usb线拔插)

作者: gale_小米 | 来源:发表于2022-11-13 17:44 被阅读0次

客户反馈问题:目前最大问题是,断电机器没有休眠 是一直在工作,只是关了显示屏,
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);
        

相关文章

  • Error: "Error obtaining UI

    在确认过自己手机android 大于4.1版本后,你可以尝试: 1、重新拔插你的USB数据线Pull out an...

  • A33 烧录

    2019-04-30 烧录 普清 插跳帽(音量键) 插usb,然后飞也似的开始一直按开关 结束后拔usb 拔跳帽 ...

  • 11-Openwrt hotplug system

    hotplug为linux的一个热拔插系统,在很多应用都有用到,如网口的拔插,USB的拔插,按键的触发...非常广...

  • USB连接问题定位

    现象:软重启设备AR9342,USB口仍旧挂载,但数据不通,通过硬件重启或者拔插USB,USB通讯正常。 问题分析...

  • Android设备通过网络adb 调试

    平时我们在Android设备上调试会遇到一系列的问题,比如Android设备的usb口没有地方再插一根线了,无法进...

  • android usb ACTION_USB_DEVICE_AT

    USB 拔插广播在开发中发现USB 在连接情况下,app 侦测 断开,因此需要添加log,查看系统是否有广播 目...

  • power on log

    1 -指令reboot , warm 2 -断电后重新上电, cold 3 -拔插dp, box重启 3.1 插入...

  • 「Do.003」 adb无线连接多台Android设备

    首台设备连接 我们在开发过程中总是会用数据线连接手机进行调试,但是经常对手机插口和电脑usb进行拔插操作终归是不好...

  • Android 无线调试设备

    背景我们都知道使用USB线连接手机是非常麻烦的事情,经常要拔插拔插,对硬件接口也是有损伤的,以下介绍两种在同一局域...

  • 黑星星

    今天因为玩投影仪电源线和团团发了一次火,他喜欢把电源线拔了插,插了拔,我警告他,再拔就不让玩投影仪了,结果很挑衅地...

网友评论

      本文标题:Android 断电休眠(指usb线拔插)

      本文链接:https://www.haomeiwen.com/subject/njblxdtx.html