Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c474bfd0 authored by Artem Iglikov's avatar Artem Iglikov
Browse files

Fix PowerManagerService handling of work chains.

When a wakelock with specific set of flags is requested
PowerManagerService crashes with NPE because
applyWakeLockFlagsOnAcquireLocked does not handle work chains and
requires UID set directly on the work source instead of the work chain.

This fixes the behavior by handling the work chains as well as
introducing additional emptiness checks.

There may be multiple work chains in a work source, and only the first
one is used. I don't know the details of this method, but it looks like
it's a reasonable decision.

Bug: 113868145
Test: atest FrameworksCoreTests:PowerManagerTest

Change-Id: Idbfa1d0cd32ddc021caf6443138688d3f8b7c946
parent a5f160fd
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@
    <uses-permission android:name="android.permission.READ_LOGS"/>
    <uses-permission android:name="android.permission.READ_LOGS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.USE_CREDENTIALS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+20 −1
Original line number Original line Diff line number Diff line
@@ -84,6 +84,25 @@ public class PowerManagerTest extends AndroidTestCase {
        fail("Bad WakeLock flag was not caught.");
        fail("Bad WakeLock flag was not caught.");
    }
    }


    /**
     * Ensure that we can have work sources with work chains when uid is not set directly on work
     * source, and that this doesn't crash system server.
     *
     * @throws Exception
     */
    @SmallTest
    public void testWakeLockWithWorkChains() throws Exception {
        PowerManager.WakeLock wakeLock = mPm.newWakeLock(
                PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
                "TEST_LOCK");
        WorkSource workSource = new WorkSource();
        WorkSource.WorkChain workChain = workSource.createWorkChain();
        workChain.addNode(1000, "test");
        wakeLock.setWorkSource(workSource);

        doTestWakeLock(wakeLock);
    }

    /**
    /**
     * Apply a few tests to a wakelock to make sure it's healthy.
     * Apply a few tests to a wakelock to make sure it's healthy.
     *
     *
+26 −5
Original line number Original line Diff line number Diff line
@@ -1079,18 +1079,39 @@ public final class PowerManagerService extends SystemService
        return false;
        return false;
    }
    }


    private static WorkChain getFirstNonEmptyWorkChain(WorkSource workSource) {
        if (workSource.getWorkChains() == null) {
            return null;
        }

        for (WorkChain workChain: workSource.getWorkChains()) {
            if (workChain.getSize() > 0) {
                return workChain;
            }
        }

        return null;
    }

    private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
    private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
        if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
        if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
                && isScreenLock(wakeLock)) {
                && isScreenLock(wakeLock)) {
            String opPackageName;
            String opPackageName;
            int opUid;
            int opUid;
            if (wakeLock.mWorkSource != null && wakeLock.mWorkSource.getName(0) != null) {
            if (wakeLock.mWorkSource != null && !wakeLock.mWorkSource.isEmpty()) {
                opPackageName = wakeLock.mWorkSource.getName(0);
                WorkSource workSource = wakeLock.mWorkSource;
                opUid = wakeLock.mWorkSource.get(0);
                WorkChain workChain = getFirstNonEmptyWorkChain(workSource);
                if (workChain != null) {
                    opPackageName = workChain.getAttributionTag();
                    opUid = workChain.getAttributionUid();
                } else {
                    opPackageName = workSource.getName(0) != null
                            ? workSource.getName(0) : wakeLock.mPackageName;
                    opUid = workSource.get(0);
                }
            } else {
            } else {
                opPackageName = wakeLock.mPackageName;
                opPackageName = wakeLock.mPackageName;
                opUid = wakeLock.mWorkSource != null ? wakeLock.mWorkSource.get(0)
                opUid = wakeLock.mOwnerUid;
                        : wakeLock.mOwnerUid;
            }
            }
            wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,
            wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,
                    opPackageName, opUid);
                    opPackageName, opUid);