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

Commit 12da4133 authored by Patrick Williams's avatar Patrick Williams
Browse files

Send SessionTag.SYSUI for sysui and launcher

Bug: 359965565
Bug: 428944983
Flag: com.android.server.power.hint.use_sysui_session_tag
Test: atest PerformanceHintTests:com.android.server.power.hint.HintManagerServiceTest
Change-Id: I8ec6fdb0969580c72f42b9999a62372c6c9ab0d0
parent 9895581f
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -150,23 +150,24 @@ java_library_static {
    ],

    libs: [
        "services.net",
        "android.frameworks.location.altitude-V2-java",
        "android.hardware.common-V2-java",
        "android.hardware.light-V2.0-java",
        "android.hardware.gnss-V2-java",
        "android.hardware.light-V2.0-java",
        "android.hardware.vibrator-V3-java",
        "androidx.annotation_annotation",
        "app-compat-annotations",
        "device_policy_aconfig_flags_lib",
        "error_prone_annotations",
        "framework-tethering.stubs.module_lib",
        "keepanno-annotations",
        "monet",
        "power_hint_flags_lib",
        "service-art.stubs.system_server",
        "service-permission.stubs.system_server",
        "service-rkp.stubs.system_server",
        "service-sdksandbox.stubs.system_server",
        "device_policy_aconfig_flags_lib",
        "services.net",
    ],
    plugins: ["ImmutabilityAnnotationProcessor"],

+62 −15
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import static com.android.internal.util.FrameworkStatsLog.GPU_HEADROOM_REPORTED_
import static com.android.internal.util.FrameworkStatsLog.GPU_HEADROOM_REPORTED__TYPE__AVERAGE;
import static com.android.internal.util.FrameworkStatsLog.GPU_HEADROOM_REPORTED__TYPE__UNKNOWN_CALCULATION_TYPE;
import static com.android.server.power.hint.Flags.resetOnForkEnabled;
import static com.android.server.power.hint.Flags.useSysuiSessionTag;

import android.Manifest;
import android.adpf.ISessionManager;
@@ -40,11 +41,14 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.IActivityManager;
import android.app.StatsManager;
import android.app.UidObserver;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.hardware.power.ChannelConfig;
import android.hardware.power.CpuHeadroomParams;
import android.hardware.power.CpuHeadroomResult;
@@ -198,6 +202,7 @@ public final class HintManagerService extends SystemService {
    private final NativeWrapper mNativeWrapper;
    private final CleanUpHandler mCleanUpHandler;

    private final IActivityManager mActivityManager;
    private final ActivityManagerInternal mAmInternal;

    private final Context mContext;
@@ -245,6 +250,8 @@ public final class HintManagerService extends SystemService {

    private ISessionManager mSessionManager;

    private int mSysuiUid = Process.INVALID_UID;

    // this cache tracks the expiration time of the items and performs cleanup on lookup
    private static class HeadroomCache<K, V> {
        final List<HeadroomCacheItem> mItemList;
@@ -325,6 +332,7 @@ public final class HintManagerService extends SystemService {
        mNativeWrapper.halInit();
        mHintSessionPreferredRate = mNativeWrapper.halGetHintSessionPreferredRate();
        mUidObserver = new MyUidObserver();
        mActivityManager = Objects.requireNonNull(injector.getIActivityManager());
        mAmInternal = Objects.requireNonNull(
                LocalServices.getService(ActivityManagerInternal.class));
        mPowerHal = injector.createIPower();
@@ -463,6 +471,9 @@ public final class HintManagerService extends SystemService {
            return IPower.Stub.asInterface(
                ServiceManager.waitForDeclaredService(IPower.DESCRIPTOR + "/default"));
        }
        IActivityManager getIActivityManager() {
            return ActivityManager.getService();
        }
    }

    private static class ThreadUsageTracker {
@@ -655,13 +666,16 @@ public final class HintManagerService extends SystemService {
    private void systemReady() {
        Slogf.v(TAG, "Initializing HintManager service...");
        try {
            ActivityManager.getService().registerUidObserver(mUidObserver,
            mActivityManager.registerUidObserver(mUidObserver,
                    ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
                    ActivityManager.PROCESS_STATE_UNKNOWN, null);
        } catch (RemoteException e) {
            // ignored; both services live in system_server
        }

        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
        mSysuiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
            PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
    }

    private void registerStatsCallbacks() {
@@ -1448,20 +1462,8 @@ public final class HintManagerService extends SystemService {
                    }
                }

                if (tag == SessionTag.APP) {
                    // If the category of the app is a game,
                    // we change the session tag to SessionTag.GAME
                    // as it was not previously classified
                    switch (getUidApplicationCategory(callingUid)) {
                        case ApplicationInfo.CATEGORY_GAME -> tag = SessionTag.GAME;
                        case ApplicationInfo.CATEGORY_UNDEFINED ->
                            // We use CATEGORY_UNDEFINED to filter the case when
                            // PackageManager.NameNotFoundException is caught,
                            // which should not happen.
                            tag = SessionTag.APP;
                        default -> tag = SessionTag.APP;
                    }
                }
                tag = updateSessionTag(tag, callingUid);

                config.id = -1;
                Long halSessionPtr = null;
                if (mConfigCreationSupport.get()) {
@@ -2121,6 +2123,51 @@ public final class HintManagerService extends SystemService {
                    powerEfficiency, graphicsPipeline);
        }

        private @SessionTag int updateSessionTag(@SessionTag int incomingTag, int callingUid) {
            if (useSysuiSessionTag() && (isUidSysui(callingUid) || isUidLauncher(callingUid))) {
                return SessionTag.SYSUI;
            }

            if (incomingTag != SessionTag.APP) {
                return incomingTag;
            }

            return switch (getUidApplicationCategory(callingUid)) {
                case ApplicationInfo.CATEGORY_GAME -> SessionTag.GAME;
                case ApplicationInfo.CATEGORY_UNDEFINED ->
                    // We use CATEGORY_UNDEFINED to filter the case when
                    // PackageManager.NameNotFoundException is caught,
                    // which should not happen.
                    SessionTag.APP;
                default -> SessionTag.APP;
            };
        }

        private boolean isUidSysui(int uid) {
            return mSysuiUid != Process.INVALID_UID && mSysuiUid == uid;
        }

        private boolean isUidLauncher(int uid) {
            RoleManager roleManager = Objects.requireNonNull(
                    mContext.getSystemService(RoleManager.class));

            List<String> packages = roleManager.getRoleHolders(RoleManager.ROLE_HOME);
            if (packages.size() != 1) {
                Slog.w(TAG, "Unexpected number of role holders for ROLE_HOME.");
                return false;
            }

            int launcherUid;
            try {
                launcherUid = mPackageManager.getPackageUid(packages.getFirst(),
                        PackageManager.MATCH_DEFAULT_ONLY);
            } catch (PackageManager.NameNotFoundException exception) {
                return false;
            }

            return uid == launcherUid;
        }

        private int getUidApplicationCategory(int uid) {
            try {
                final String packageName = mPackageManager.getNameForUid(uid);
+5 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ android_test {
        "androidx.test.rules",
        "flag-junit",
        "junit",
        "mockito-target-minus-junit4",
        "mockito-target-extended-minus-junit4",
        "platform-test-annotations",
        "services.core",
        "truth",
@@ -21,6 +21,10 @@ android_test {
    libs: [
        "android.test.base.stubs.system",
    ],
    jni_libs: [
        "libdexmakerjvmtiagent",
        "libstaticjvmtiagent",
    ],
    test_suites: [
        "automotive-tests",
        "device-tests",
+2 −0
Original line number Diff line number Diff line
@@ -20,4 +20,6 @@
    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.server.power.hinttests"
         android:label="ADPF Performance Hint Service Test"/>

    <application android:debuggable="true" />
</manifest>
+108 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.power.hint;


import static com.android.server.power.hint.Flags.FLAG_USE_SYSUI_SESSION_TAG;
import static com.android.server.power.hint.HintManagerService.CLEAN_UP_UID_DELAY_MILLIS;

import static com.google.common.truth.Truth.assertThat;
@@ -45,9 +46,13 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.IActivityManager;
import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.hardware.common.fmq.MQDescriptor;
import android.hardware.power.ChannelConfig;
import android.hardware.power.ChannelMessage;
@@ -70,6 +75,7 @@ import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.SessionCreationConfig;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -79,6 +85,7 @@ import androidx.test.InstrumentationRegistry;

import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.power.hint.HintManagerService.AppHintSession;
import com.android.server.power.hint.HintManagerService.Injector;
import com.android.server.power.hint.HintManagerService.NativeWrapper;
@@ -160,10 +167,16 @@ public class HintManagerServiceTest {
    @Mock
    private IPower mIPowerMock;
    @Mock
    private IActivityManager mIActivityManagerMock;
    @Mock
    private ActivityManagerInternal mAmInternalMock;
    @Mock
    private PackageManager mMockPackageManager;
    @Mock
    private RoleManager mMockRoleManager;
    @Mock
    private PackageManagerInternal mPackageManagerInternalMock;
    @Mock
    private IHintManager.IHintManagerClient mClientCallback;
    @Rule
    public final CheckFlagsRule mCheckFlagsRule =
@@ -214,6 +227,7 @@ public class HintManagerServiceTest {
        applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
        mSupportInfo = makeDefaultSupportInfo();
        when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
        when(mContext.getSystemService(RoleManager.class)).thenReturn(mMockRoleManager);
        when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME);
        when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt()))
                .thenReturn(applicationInfo);
@@ -244,6 +258,8 @@ public class HintManagerServiceTest {
        when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo);
        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
        LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
        LocalServices.removeServiceForTest(PackageManagerInternal.class);
        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
    }

    @After
@@ -334,7 +350,13 @@ public class HintManagerServiceTest {
            IPower createIPower() {
                return mIPowerMock;
            }
            IActivityManager getIActivityManager() {
                return mIActivityManagerMock;
            }
        });
        when(mPackageManagerInternalMock.getSystemUiServiceComponent())
                .thenReturn(new ComponentName("", ""));
        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        return mService;
    }

@@ -379,6 +401,92 @@ public class HintManagerServiceTest {
                        SessionTag.OTHER, creationConfig, config));
    }

    @Test
    public void testCreateHintSessionNoChangeToSessionTag() throws Exception {
        HintManagerService service = createService();
        IBinder token = new Binder();
        SessionCreationConfig creationConfig =
                makeSessionCreationConfig(new int[]{TID}, DEFAULT_TARGET_DURATION);
        SessionConfig config = new SessionConfig();
        int tag = SessionTag.OTHER;

        service.getBinderServiceInstance()
                .createHintSessionWithConfig(token, tag, creationConfig, config);

        verify(mNativeWrapperMock).halCreateHintSessionWithConfig(
                anyInt(), anyInt(), any(), anyLong(), eq(tag), any());
    }

    @Test
    public void testCreateHintSessionUpdatesAppTagToGame() throws Exception {
        ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
        when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenReturn(applicationInfo);
        HintManagerService service = createService();
        IBinder token = new Binder();
        SessionCreationConfig creationConfig =
                makeSessionCreationConfig(new int[]{TID}, DEFAULT_TARGET_DURATION);
        SessionConfig config = new SessionConfig();

        service.getBinderServiceInstance()
                .createHintSessionWithConfig(token, SessionTag.APP, creationConfig, config);

        verify(mNativeWrapperMock).halCreateHintSessionWithConfig(
                anyInt(), anyInt(), any(), anyLong(), eq(SessionTag.GAME), any());
    }

    @Test
    public void testCreateHintSessionAppTagUnchanged() throws Exception {
        ApplicationInfo applicationInfo = new ApplicationInfo();
        when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenReturn(applicationInfo);
        HintManagerService service = createService();
        IBinder token = new Binder();
        SessionCreationConfig creationConfig =
                makeSessionCreationConfig(new int[]{TID}, DEFAULT_TARGET_DURATION);
        SessionConfig config = new SessionConfig();

        service.getBinderServiceInstance()
                .createHintSessionWithConfig(token, SessionTag.APP, creationConfig, config);

        verify(mNativeWrapperMock).halCreateHintSessionWithConfig(
                anyInt(), anyInt(), any(), anyLong(), eq(SessionTag.APP), any());
    }

    @RequiresFlagsEnabled(FLAG_USE_SYSUI_SESSION_TAG)
    @Test
    public void testCreateHintSessionSetsSysuiTagWhenCallerIsSysui() throws Exception {
        when(mPackageManagerInternalMock.getPackageUid(any(), anyLong(), anyInt())).thenReturn(UID);
        HintManagerService service = createService();
        IBinder token = new Binder();
        SessionCreationConfig creationConfig =
                makeSessionCreationConfig(new int[]{TID}, DEFAULT_TARGET_DURATION);
        SessionConfig config = new SessionConfig();

        service.getBinderServiceInstance()
                .createHintSessionWithConfig(token, SessionTag.APP, creationConfig, config);

        verify(mNativeWrapperMock).halCreateHintSessionWithConfig(
                anyInt(), anyInt(), any(), anyLong(), eq(SessionTag.SYSUI), any());
    }

    @RequiresFlagsEnabled(FLAG_USE_SYSUI_SESSION_TAG)
    @Test
    public void testCreateHintSessionSetsSysuiTagWhenCallerIsLauncher() throws Exception {
        when(mMockRoleManager.getRoleHolders(any())).thenReturn(List.of("<mock-package-name>"));
        when(mMockPackageManager.getPackageUid(any(), anyInt())).thenReturn(UID);
        HintManagerService service = createService();
        IBinder token = new Binder();
        SessionCreationConfig creationConfig =
                makeSessionCreationConfig(new int[]{TID}, DEFAULT_TARGET_DURATION);
        SessionConfig config = new SessionConfig();

        service.getBinderServiceInstance()
                .createHintSessionWithConfig(token, SessionTag.APP, creationConfig, config);

        verify(mNativeWrapperMock).halCreateHintSessionWithConfig(
                anyInt(), anyInt(), any(), anyLong(), eq(SessionTag.SYSUI), any());
    }

    @Test
    public void testCreateHintSessionFallback() throws Exception {
        HintManagerService service = createService();