When playing music first, execute the adb command:
adb shell dumpsys power|grep -i wake
Take playing NetEase Cloud Music as an example:
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=false
Wake 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
The tag of wakeLock is "AudioMixAudioOut_D", we can use this tag to determine whether it is a music application, then how to determine whether it is playing music, let’s analyze
framewroks\base\core\java\android\os\PowerManagerInternal.java has an internal interface 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);
}
Take the power saving function of Spreadtrum as an example:
First implement the PowerControllerInternalCallback interface:
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);
}
}
Then register this WakeLockObserver to PowerManagerInternal
mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class);
......
mLocalPowerManager.registerPowerControllerInternalCallback(mWakeLockObserver);
PowerManagerInternal.java is an abstract class, the internal class LocalService in PowerManagerService.java inherits PowerManagerInternal
In this way, when the system detects that there is a wakelock application, it will call the onWakeLockAcquired() method
The general process of acquire WakeLock at the app layer is as follows:
1. frameworks/base/core/java/android/os/PowerManager.java
acquire--->acquireLocked---->PowerManagerService.acquireWakeLock
2. frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
-->acquireWakeLock
-->acquireWakeLockInternal
-->updatePowerStateLocked
-->updateSuspendBlockerLocked
-->updatePowerStateLocked
-->updateSuspendBlockerLocked
-->mWakeLockSuspendBlocker.acquire
-->PowerManagerService$SuspendBlockerImpl.acquire-->nativeAcquireSuspendBlocker
3. frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
nativeAcquireSuspendBlocker-->acquire_wake_lock
Back to our theme
PowerManagerService.java-->acquireWakeLockInternal() will call the method we need 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 is an internal class added by Spreadtrum in 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);
}
}
}
It is judged here that the level of the lock is PARTIAL_WAKE_LOCK, and then judge whether the process uid is AUDIOSERVER_UID
/**
* Defines the UID/GID for the audioserver process.
* @hide
*/
public static final int AUDIOSERVER_UID = 1041;
First add a description of WakeLock levelAndFlags and usage scenarios
In addition to these four levels, PowerMager also provides two Flags, which can be used with Levels.
Now look back at notifyWakeLockAcquiredLocked(). If the judgment conditions of PARTIAL_WAKE_LOCK and AUDIOSERVER_UID are met, the onWakeLockAcquired() method in the interface PowerControllerInternalCallback we mentioned above will be called.
Now walk into the onWakeLockAcquired() of WakelockConstraintHelper.java
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<Integer> uids = new ArrayList();
if (workSource != null) {
int num = workSource.size();
int count = 0;
for (; count<num; count++) {
uids.add(workSource.get(count));
}
}
if (DEBUG) Slog.d(TAG, "noteAudioWakeLockAcquired: tag: " + tag + " uid size:" + uids.size());
if (isAudioIn(tag)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_AUDIOIN_WAKELOCK_UPDATED, uids));
} else if (isAudioOut(tag)) {
WakeLockInfo wakeLockInfo = new WakeLockInfo(tag, packageName, ownerUid, workSource);
mHandler.sendMessage(mHandler.obtainMessage(MSG_AUDIOOUT_WAKELOCK_UPDATED, wakeLockInfo));
}
//} catch (Exception e) {}
}
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;
}
When it is necessary to judge whether music is playing, it will combine this mAudioFlag and isMusicActive() of AudioManager to judge whether music is playing
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;
}