Android determines whether the app is playing music

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;
    }

 

 

Guess you like

Origin blog.csdn.net/liu362732346/article/details/104969465