Android 判断app是否正在播放音乐
首先播放音乐的时候,执行下adb命令:
adb shell dumpsys power|grep -i wake
以播放网易云音乐为例:
C:\Users\Administrator>adb shell dumpsys power| findstr -i wake no_cached_wake_locks=true mWakefulness=Awake mWakefulnessChanging=false mWakeLockSummary=0x1 mLastWakeTime=187182227 (24697 ms ago) mHoldingWakeLockSuspendBlocker=true mWakeUpWhenPluggedOrUnpluggedConfig=true mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=false mDrawWakeLockOverrideFromSidekick=false mDoubleTapWakeEnabled=falseWake Locks: size=2 PARTIAL_WAKE_LOCK 'AudioMixAudioOut_D' ACQ=-831ms (uid=1041 ws=WorkSource{10139}) PARTIAL_WAKE_LOCK 'com.netease.cloudmusic.module.player.NeteaseAudioPlayer' ON_AFTER_RELEASE ACQ=-1s168ms (uid=10139 pid=26062) PowerManagerService.WakeLocks: ref count=1
wakeLock的tag标志是‘’AudioMixAudioOut_D‘’,我们就可以通过这个tag来判断是不是音乐类的应用,那怎么判断是否正在播放音乐呢,下面开始分析
framewroks\base\core\java\android\os\PowerManagerInternal.java有个内部接口PowerControllerInternalCallback
public interface PowerControllerInternalCallback { public void onWakeLockAcquired(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource); public void onWakeLockReleased(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource); public void onWakeLockChanging(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource, String newTag, String newPackageName, int newOwnerUid, int newOwnerPid, WorkSource newWorkSource); public void onConstraintAppAcquireWakeLock(long nowElapsed, long wakelockStartTime); }
已展讯省电功能为例:
首先实现PowerControllerInternalCallback接口:
frameworks\base\services\core\java\com\android\server\power\sprdpower\WakelockConstraintHelper.java
private class WakeLockObserver implements PowerManagerInternal.PowerControllerInternalCallback { @Override public void onWakeLockAcquired(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource) { noteAudioWakeLockAcquired(tag, packageName, ownerUid, ownerPid, workSource); } @Override public void onWakeLockReleased(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource) { noteAudioWakeLockReleased(tag, packageName, ownerUid, ownerPid, workSource); } @Override public void onWakeLockChanging(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource,String newTag, String newPackageName, int newOwnerUid, int newOwnerPid, WorkSource newWorkSource) { noteAudioWakeLockChanging(tag, packageName, ownerUid, ownerPid, workSource, newTag, newPackageName, newOwnerUid, newOwnerPid, newWorkSource); } @Override public void onConstraintAppAcquireWakeLock(long nowElapsed, long wakelockStartTime) { noteConstraintAppAcquireWakeLock(nowElapsed, wakelockStartTime); } }
再将这个WakeLockObserver注册到PowerManagerInternal
mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);......mLocalPowerManager.registerPowerControllerInternalCallback(mWakeLockObserver);
PowerManagerInternal.java是个抽象类,在PowerManagerService.java中的内部类LocalService继承了PowerManagerInternal
这样当系统监听到有wakelock申请就会调用onWakeLockAcquired()方法
app层acquire WakeLock的大致流程如下:
1. frameworks/base/core/java/android/os/PowerManager.java acquire--->acquireLocked---->PowerManagerService.acquireWakeLock2. frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java -->acquireWakeLock -->acquireWakeLockInternal -->updatePowerStateLocked -->updateSuspendBlockerLocked -->updatePowerStateLocked -->updateSuspendBlockerLocked -->mWakeLockSuspendBlocker.acquire -->PowerManagerService$SuspendBlockerImpl.acquire-->nativeAcquireSuspendBlocker3. frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp nativeAcquireSuspendBlocker-->acquire_wake_lock
回归我们的主题
PowerManagerService.java-->acquireWakeLockInternal()就会调用我们需要的方法notifyWakeLockAcquiredLocked()
private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) { if (mSystemReady && !wakeLock.mDisabled) { wakeLock.mNotifiedAcquired = true; mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource, wakeLock.mHistoryTag); restartNofifyLongTimerLocked(wakeLock); // NOTE: Bug #627645 low power Feature BEG--> // notify listeners mPowerControllerHelper.notifyWakeLockAcquiredLocked(wakeLock); // <-- NOTE: Bug #627645 low power Feature END } }
PowerControllerHelper是展讯在PowerManagerService.java增加的一个内部类
PowerControllerHelper-->notifyWakeLockAcquiredLocked()
public void notifyWakeLockAcquiredLocked(WakeLock wakeLock) { if (wakeLock.mStartAcquireTimeStamp <= 0) { wakeLock.mStartAcquireTimeStamp = SystemClock.elapsedRealtime(); } else { Slog.d(TAG, "call notifyWakeLockAcquiredLocked > 1, wake lock:" + wakeLock.mTag + " from " + wakeLock.mPackageName + "(" + wakeLock.mOwnerUid +")"); } // if Audio acquired a wakelock notify listeners if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) == PowerManager.PARTIAL_WAKE_LOCK && Process.AUDIOSERVER_UID == wakeLock.mOwnerUid) { if (mPowerControllerInternalCallback != null) { mPowerControllerInternalCallback.onWakeLockAcquired(wakeLock.mTag, wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource); } } }
在这里判断锁的level等级是PARTIAL_WAKE_LOCK,再判断进程uid是不是AUDIOSERVER_UID
/** * Defines the UID/GID for the audioserver process. * @hide */ public static final int AUDIOSERVER_UID = 1041;
先补充说明下WakeLock levelAndFlags和使用场景
除了这四个Level之外,PowerMager还提供了两个Flag,可以配合Level使用。
现在再回过头看notifyWakeLockAcquiredLocked(),如果满足PARTIAL_WAKE_LOCK和AUDIOSERVER_UID的判断条件就会调用我们上面说的接口PowerControllerInternalCallback里的onWakeLockAcquired()方法了
现在就走进了WakelockConstraintHelper.java的onWakeLockAcquired()中
public void onWakeLockAcquired(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource) { noteAudioWakeLockAcquired(tag, packageName, ownerUid, ownerPid, workSource); }
private void noteAudioWakeLockAcquired(String tag, String packageName, int ownerUid, int ownerPid, WorkSource workSource) { if (DEBUG) Slog.d(TAG, "noteAudioWakeLockAcquired: workSource:" + workSource); // only care about the workSource if (workSource == null) return; if (!AUDIO_PACKAGE_NAME.equals(packageName) || Process.AUDIOSERVER_UID != ownerUid) return; //try { ArrayList uids = new ArrayList(); if (workSource != null) { int num = workSource.size(); int count = 0; for (; count
case MSG_AUDIOOUT_WAKELOCK_UPDATED: handleAudioOutWakeLockUpdated((WakeLockInfo)msg.obj); break;
private void handleAudioOutWakeLockUpdated(WakeLockInfo wakeLockInfo) { ...... appState.updateAudioState(audioFlag); ......}
public void updateAudioState(int audioState) { if (mAudioFlag != audioState && (audioState & AUDIO_TYPE_OUT) != 0) { mLastTimePlayingMusicSeen = SystemClock.elapsedRealtime(); } mAudioFlag = audioState; }
public boolean isPlayingMusic() { return (mAudioFlag & AUDIO_TYPE_OUT) != 0; }
当需要判断是否在播放音乐的时候,就会结合这个mAudioFlag和AudioManager的isMusicActive()来判断是否正在播放音乐
private boolean isPlayingMusicInternal(AppState appState) { if (appState.mPlayingMusic) return true; if(mAudioManager != null && !mAudioManager.isMusicActive() /*&& !mAudioManager.isFmActive()*/){ return false; } if (DEBUG_MORE) Slog.d(TAG, "mAudioManager.isMusicActive(): " + mAudioManager.isMusicActive() + " getMode():" + mAudioManager.getMode()); boolean playing = appState.isPlayingMusic(); // if app is still playing music after system standby for APP_PLAYING_MUSIC_THRESHOLD // set app to be playing music if (playing && mStandbyStartTime > 0) { long standbyDuration = SystemClock.elapsedRealtime() - mStandbyStartTime; if (standbyDuration > APP_PLAYING_MUSIC_THRESHOLD) appState.setPlayingMusicState(true); } return playing; }
更多相关文章
- Java中的匿名内部类:由setOnClickListener说起
- 获取Android各类系统相关信息的接口实现代码
- Android 利用AudioManager控制后台音乐播放器暂停,播放
- 内部类联想到Android的Listener
- 基于Service与ContentProvider的音乐播放实例!
- Android Studio自动化快速实现Parcelable接口序列化
- Android 接口定义语言AIdl
- Android高仿网易云音乐播放界面
- android如何在xml中引用内部类