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

Commit c605f427 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Merge cherrypicks of ['googleplex-android-review.googlesource.com/30842514'] into 25Q2-release.

Change-Id: I9810638eb6c562aeaa9e7d58a10f66cdc010d966
parents fdeaf959 52cf00a9
Loading
Loading
Loading
Loading
+11 −23
Original line number Diff line number Diff line
@@ -21,13 +21,11 @@ import android.os.CpuHeadroomParamsInternal;
import android.os.GpuHeadroomParamsInternal;
import android.os.IHintSession;
import android.os.SessionCreationConfig;

import android.hardware.power.ChannelConfig;
import android.hardware.power.CpuHeadroomResult;
import android.hardware.power.ChannelConfig;
import android.hardware.power.GpuHeadroomResult;
import android.hardware.power.SessionConfig;
import android.hardware.power.SessionTag;
import android.hardware.power.SupportInfo;

/** {@hide} */
interface IHintManager {
@@ -42,6 +40,11 @@ interface IHintManager {
    IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag,
            in SessionCreationConfig creationConfig, out SessionConfig config);

    /**
     * Get preferred rate limit in nanoseconds.
     */
    long getHintSessionPreferredRate();

    void setHintSessionThreads(in IHintSession hintSession, in int[] tids);
    int[] getHintSessionThreadIds(in IHintSession hintSession);

@@ -58,28 +61,13 @@ interface IHintManager {
    long getGpuHeadroomMinIntervalMillis();

    /**
     * Used by the JNI to pass an interface to the SessionManager;
     * for internal use only.
     */
    oneway void passSessionManagerBinder(in IBinder sessionManager);

    parcelable HintManagerClientData {
        int powerHalVersion;
        int maxGraphicsPipelineThreads;
        long preferredRateNanos;
        SupportInfo supportInfo;
    }

    interface IHintManagerClient {
        /**
        * Returns FMQ channel information for the caller, which it associates to the callback binder lifespan.
     * Get Maximum number of graphics pipeline threads allowed per-app.
     */
        oneway void receiveChannelConfig(in ChannelConfig config);
    }
    int getMaxGraphicsPipelineThreadsCount();

    /**
     * Set up an ADPF client, receiving a remote client binder interface and
     * passing back a bundle of support and configuration information.
     * Used by the JNI to pass an interface to the SessionManager;
     * for internal use only.
     */
    HintManagerClientData registerClient(in IHintManagerClient client);
    oneway void passSessionManagerBinder(in IBinder sessionManager);
}
+42 −72
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@
#include <aidl/android/hardware/power/SessionHint.h>
#include <aidl/android/hardware/power/SessionMode.h>
#include <aidl/android/hardware/power/SessionTag.h>
#include <aidl/android/hardware/power/SupportInfo.h>
#include <aidl/android/hardware/power/WorkDuration.h>
#include <aidl/android/hardware/power/WorkDurationFixedV1.h>
#include <aidl/android/os/IHintManager.h>
@@ -149,36 +148,10 @@ private:
    std::future<bool> mChannelCreationFinished;
};

class SupportInfoWrapper {
public:
    SupportInfoWrapper(hal::SupportInfo& info);
    bool isSessionModeSupported(hal::SessionMode mode);
    bool isSessionHintSupported(hal::SessionHint hint);

private:
    template <class T>
    bool getEnumSupportFromBitfield(T& enumValue, int64_t& supportBitfield) {
        // extract the bit corresponding to the enum by shifting the bitfield
        // over that much and cutting off any extra values
        return (supportBitfield >> static_cast<int>(enumValue)) % 2;
    }
    hal::SupportInfo mSupportInfo;
};

class HintManagerClient : public IHintManager::BnHintManagerClient {
public:
    // Currently a no-op that exists for FMQ init to call in the future
    ndk::ScopedAStatus receiveChannelConfig(const hal::ChannelConfig&) {
        return ndk::ScopedAStatus::ok();
    }
};

struct APerformanceHintManager {
public:
    static APerformanceHintManager* getInstance();
    APerformanceHintManager(std::shared_ptr<IHintManager>& service,
                            IHintManager::HintManagerClientData&& clientData,
                            std::shared_ptr<HintManagerClient> callbackClient);
    APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
    APerformanceHintManager() = delete;
    ~APerformanceHintManager();

@@ -196,21 +169,29 @@ public:
    FMQWrapper& getFMQWrapper();
    bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
    void initJava(JNIEnv* _Nonnull env);
    ndk::ScopedAIBinder_Weak x;
    template <class T>
    static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
                                         ASurfaceControl** controls, int numSurfaceControls,
                                         std::vector<T>& out);
    ndk::SpAIBinder& getToken();
    SupportInfoWrapper& getSupportInfo();

private:
    // Necessary to create an empty binder object
    static void* tokenStubOnCreate(void*) {
        return nullptr;
    }
    static void tokenStubOnDestroy(void*) {}
    static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
                                               AParcel*) {
        return STATUS_OK;
    }

    static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);

    std::shared_ptr<IHintManager> mHintManager;
    std::shared_ptr<HintManagerClient> mCallbackClient;
    IHintManager::HintManagerClientData mClientData;
    SupportInfoWrapper mSupportInfoWrapper;
    ndk::SpAIBinder mToken;
    const int64_t mPreferredRateNanos;
    std::optional<int32_t> mMaxGraphicsPipelineThreadsCount;
    FMQWrapper mFMQWrapper;
    double mHintBudget = kMaxLoadHintsPerInterval;
    int64_t mLastBudgetReplenish = 0;
@@ -292,27 +273,14 @@ static FMQWrapper& getFMQ() {
    return APerformanceHintManager::getInstance()->getFMQWrapper();
}

// ===================================== SupportInfoWrapper implementation

SupportInfoWrapper::SupportInfoWrapper(hal::SupportInfo& info) : mSupportInfo(info) {}

bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) {
    return getEnumSupportFromBitfield(hint, mSupportInfo.sessionHints);
}

bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) {
    return getEnumSupportFromBitfield(mode, mSupportInfo.sessionModes);
}

// ===================================== APerformanceHintManager implementation
APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
                                                 IHintManager::HintManagerClientData&& clientData,
                                                 std::shared_ptr<HintManagerClient> callbackClient)
      : mHintManager(std::move(manager)),
        mCallbackClient(callbackClient),
        mClientData(clientData),
        mSupportInfoWrapper(clientData.supportInfo),
        mToken(callbackClient->asBinder()) {
                                                 int64_t preferredRateNanos)
      : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
    static AIBinder_Class* tokenBinderClass =
            AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
                                  tokenStubOnTransact);
    mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
    if (mFMQWrapper.isSupported()) {
        mFMQWrapper.setToken(mToken);
        mFMQWrapper.startChannel(mHintManager.get());
@@ -347,17 +315,16 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa
        ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
        return nullptr;
    }
    std::shared_ptr<HintManagerClient> client = ndk::SharedRefBase::make<HintManagerClient>();
    IHintManager::HintManagerClientData clientData;
    ndk::ScopedAStatus ret = manager->registerClient(client, &clientData);
    int64_t preferredRateNanos = -1L;
    ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
    if (!ret.isOk()) {
        ALOGE("%s: PerformanceHint is not supported. %s", __FUNCTION__, ret.getMessage());
        ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
        return nullptr;
    }
    if (clientData.preferredRateNanos <= 0) {
        clientData.preferredRateNanos = -1L;
    if (preferredRateNanos <= 0) {
        preferredRateNanos = -1L;
    }
    return new APerformanceHintManager(manager, std::move(clientData), client);
    return new APerformanceHintManager(manager, preferredRateNanos);
}

bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
@@ -422,9 +389,7 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
        ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
        return nullptr;
    }

    auto out = new APerformanceHintSession(mHintManager, std::move(session),
                                           mClientData.preferredRateNanos,
    auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
                                           sessionCreationConfig->targetWorkDurationNanos, isJava,
                                           sessionConfig.id == -1
                                                   ? std::nullopt
@@ -451,11 +416,24 @@ APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env
}

int64_t APerformanceHintManager::getPreferredRateNanos() const {
    return mClientData.preferredRateNanos;
    return mPreferredRateNanos;
}

int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() {
    return mClientData.maxGraphicsPipelineThreads;
    if (!mMaxGraphicsPipelineThreadsCount.has_value()) {
        int32_t threadsCount = -1;
        ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount);
        if (!ret.isOk()) {
            ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s",
                  __FUNCTION__, ret.getMessage());
            return -1;
        }
        if (threadsCount <= 0) {
            threadsCount = -1;
        }
        mMaxGraphicsPipelineThreadsCount.emplace(threadsCount);
    }
    return mMaxGraphicsPipelineThreadsCount.value();
}

FMQWrapper& APerformanceHintManager::getFMQWrapper() {
@@ -472,14 +450,6 @@ void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
    mJavaInitialized = true;
}

ndk::SpAIBinder& APerformanceHintManager::getToken() {
    return mToken;
}

SupportInfoWrapper& APerformanceHintManager::getSupportInfo() {
    return mSupportInfoWrapper;
}

// ===================================== APerformanceHintSession implementation

constexpr int kNumEnums = enum_size<hal::SessionHint>();
+13 −22
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ public:
                 const SessionCreationConfig& creationConfig, hal::SessionConfig* config,
                 std::shared_ptr<IHintSession>* _aidl_return),
                (override));
    MOCK_METHOD(ScopedAStatus, getHintSessionPreferredRate, (int64_t * _aidl_return), (override));
    MOCK_METHOD(ScopedAStatus, getMaxGraphicsPipelineThreadsCount, (int32_t* _aidl_return),
                (override));
    MOCK_METHOD(ScopedAStatus, setHintSessionThreads,
                (const std::shared_ptr<IHintSession>& hintSession,
                 const ::std::vector<int32_t>& tids),
@@ -81,11 +84,6 @@ public:
    MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return),
                (override));
    MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager));
    MOCK_METHOD(ScopedAStatus, registerClient,
                (const std::shared_ptr<::aidl::android::os::IHintManager::IHintManagerClient>&
                         clientDataIn,
                 ::aidl::android::os::IHintManager::HintManagerClientData* _aidl_return),
                (override));
    MOCK_METHOD(SpAIBinder, asBinder, (), (override));
    MOCK_METHOD(bool, isRemote, (), (override));
};
@@ -127,9 +125,10 @@ public:

    APerformanceHintManager* createManager() {
        APerformanceHint_setUseFMQForTesting(mUsingFMQ);
        ON_CALL(*mMockIHintManager, registerClient(_, _))
                .WillByDefault(
                        DoAll(SetArgPointee<1>(mClientData), [] { return ScopedAStatus::ok(); }));
        ON_CALL(*mMockIHintManager, getHintSessionPreferredRate(_))
                .WillByDefault(DoAll(SetArgPointee<0>(123L), [] { return ScopedAStatus::ok(); }));
        ON_CALL(*mMockIHintManager, getMaxGraphicsPipelineThreadsCount(_))
                .WillByDefault(DoAll(SetArgPointee<0>(5), [] { return ScopedAStatus::ok(); }));
        return APerformanceHint_getManager();
    }

@@ -239,20 +238,6 @@ public:
    int kMockQueueSize = 20;
    bool mUsingFMQ = false;

    IHintManager::HintManagerClientData mClientData{
            .powerHalVersion = 6,
            .maxGraphicsPipelineThreads = 5,
            .preferredRateNanos = 123L,
            .supportInfo{
                    .usesSessions = true,
                    .boosts = 0,
                    .modes = 0,
                    .sessionHints = -1,
                    .sessionModes = -1,
                    .sessionTags = -1,
            },
    };

    int32_t mMaxLoadHintsPerInterval;
    int64_t mLoadHintInterval;

@@ -271,6 +256,12 @@ bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) {
            lhs.gpuDurationNanos == rhs.gpuDurationNanos && lhs.durationNanos == rhs.durationNanos;
}

TEST_F(PerformanceHintTest, TestGetPreferredUpdateRateNanos) {
    APerformanceHintManager* manager = createManager();
    int64_t preferredUpdateRateNanos = APerformanceHint_getPreferredUpdateRateNanos(manager);
    EXPECT_EQ(123L, preferredUpdateRateNanos);
}

TEST_F(PerformanceHintTest, TestSession) {
    APerformanceHintManager* manager = createManager();
    APerformanceHintSession* session = createSession(manager);
+10 −49
Original line number Diff line number Diff line
@@ -296,11 +296,7 @@ public final class HintManagerService extends SystemService {
        mPowerHalVersion = 0;
        mUsesFmq = false;
        if (mPowerHal != null) {
            try {
            mSupportInfo = getSupportInfo();
            } catch (RemoteException e) {
                throw new IllegalStateException("Could not contact PowerHAL!", e);
            }
        }
        mDefaultCpuHeadroomCalculationWindowMillis =
                new CpuHeadroomParamsInternal().calculationWindowMillis;
@@ -318,7 +314,7 @@ public final class HintManagerService extends SystemService {
        }
    }

    SupportInfo getSupportInfo() throws RemoteException {
    SupportInfo getSupportInfo() {
        try {
            mPowerHalVersion = mPowerHal.getInterfaceVersion();
            if (mPowerHalVersion >= 6) {
@@ -329,40 +325,9 @@ public final class HintManagerService extends SystemService {
        }

        SupportInfo supportInfo = new SupportInfo();
        supportInfo.usesSessions = isHintSessionSupported();
        // Global boosts & modes aren't currently relevant for HMS clients
        supportInfo.boosts = 0;
        supportInfo.modes = 0;
        supportInfo.sessionHints = 0;
        supportInfo.sessionModes = 0;
        supportInfo.sessionTags = 0;

        supportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
        supportInfo.headroom.isCpuSupported = false;
        supportInfo.headroom.isGpuSupported = false;
        if (isHintSessionSupported()) {
            if (mPowerHalVersion == 4) {
                // Assume we support the V4 hints & modes unless specified
                // otherwise; this is to avoid breaking backwards compat
                // since we historically just assumed they were.
                supportInfo.sessionHints = 31; // first 5 bits are ones
            }
            if (mPowerHalVersion == 5) {
                // Assume we support the V5 hints & modes unless specified
                // otherwise; this is to avoid breaking backwards compat
                // since we historically just assumed they were.

                // Hal V5 has 8 modes, all of which it assumes are supported,
                // so we represent that by having the first 8 bits set
                supportInfo.sessionHints = 255; // first 8 bits are ones
                // Hal V5 has 1 mode which it assumes is supported, so we
                // represent that by having the first bit set
                supportInfo.sessionModes = 1;
                // Hal V5 has 5 tags, all of which it assumes are supported,
                // so we represent that by having the first 5 bits set
                supportInfo.sessionTags = 31;
            }
        }
        return supportInfo;
    }

@@ -1263,7 +1228,7 @@ public final class HintManagerService extends SystemService {
                    @SessionTag int tag, SessionCreationConfig creationConfig,
                    SessionConfig config) {
            if (!isHintSessionSupported()) {
                throw new UnsupportedOperationException("PowerHintSessions are not supported!");
                throw new UnsupportedOperationException("PowerHAL is not supported!");
            }

            java.util.Objects.requireNonNull(token);
@@ -1459,6 +1424,12 @@ public final class HintManagerService extends SystemService {
            removeChannelItem(callingTgid, callingUid);
        };

        @Override
        public long getHintSessionPreferredRate() {
            return mHintSessionPreferredRate;
        }

        @Override
        public int getMaxGraphicsPipelineThreadsCount() {
            return MAX_GRAPHICS_PIPELINE_THREADS_COUNT;
        }
@@ -1590,16 +1561,6 @@ public final class HintManagerService extends SystemService {
            mSessionManager = ISessionManager.Stub.asInterface(sessionManager);
        }

        public IHintManager.HintManagerClientData
                registerClient(@NonNull IHintManager.IHintManagerClient clientBinder) {
            IHintManager.HintManagerClientData out = new IHintManager.HintManagerClientData();
            out.preferredRateNanos = mHintSessionPreferredRate;
            out.maxGraphicsPipelineThreads = getMaxGraphicsPipelineThreadsCount();
            out.powerHalVersion = mPowerHalVersion;
            out.supportInfo = mSupportInfo;
            return out;
        }

        @Override
        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
@@ -1607,7 +1568,7 @@ public final class HintManagerService extends SystemService {
            }
            pw.println("HintSessionPreferredRate: " + mHintSessionPreferredRate);
            pw.println("MaxGraphicsPipelineThreadsCount: " + MAX_GRAPHICS_PIPELINE_THREADS_COUNT);
            pw.println("Hint Session Support: " + isHintSessionSupported());
            pw.println("HAL Support: " + isHintSessionSupported());
            pw.println("Active Sessions:");
            synchronized (mLock) {
                for (int i = 0; i < mActiveSessions.size(); i++) {
+8 −90
Original line number Diff line number Diff line
@@ -64,7 +64,6 @@ import android.os.Binder;
import android.os.CpuHeadroomParamsInternal;
import android.os.GpuHeadroomParamsInternal;
import android.os.IBinder;
import android.os.IHintManager;
import android.os.IHintSession;
import android.os.PerformanceHintManager;
import android.os.Process;
@@ -155,8 +154,6 @@ public class HintManagerServiceTest {
    private ActivityManagerInternal mAmInternalMock;
    @Mock
    private PackageManager mMockPackageManager;
    @Mock
    private IHintManager.IHintManagerClient mClientCallback;
    @Rule
    public final CheckFlagsRule mCheckFlagsRule =
            DeviceFlagsValueProvider.createCheckFlagsRule();
@@ -174,23 +171,6 @@ public class HintManagerServiceTest {
        };
    }

    private SupportInfo makeDefaultSupportInfo() {
        mSupportInfo = new SupportInfo();
        mSupportInfo.usesSessions = true;
        // By default, mark everything as fully supported
        mSupportInfo.sessionHints = -1;
        mSupportInfo.sessionModes = -1;
        mSupportInfo.modes = -1;
        mSupportInfo.boosts = -1;
        mSupportInfo.sessionTags = -1;
        mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
        mSupportInfo.headroom.isCpuSupported = true;
        mSupportInfo.headroom.cpuMinIntervalMillis = 2000;
        mSupportInfo.headroom.isGpuSupported = true;
        mSupportInfo.headroom.gpuMinIntervalMillis = 2000;
        return mSupportInfo;
    }

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
@@ -201,7 +181,12 @@ public class HintManagerServiceTest {
        mConfig.eventFlagDescriptor = new MQDescriptor<Byte, Byte>();
        ApplicationInfo applicationInfo = new ApplicationInfo();
        applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
        mSupportInfo = makeDefaultSupportInfo();
        mSupportInfo = new SupportInfo();
        mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
        mSupportInfo.headroom.isCpuSupported = true;
        mSupportInfo.headroom.cpuMinIntervalMillis = 2000;
        mSupportInfo.headroom.isGpuSupported = true;
        mSupportInfo.headroom.gpuMinIntervalMillis = 2000;
        when(mContext.getPackageManager()).thenReturn(mMockPackageManager);
        when(mMockPackageManager.getNameForUid(anyInt())).thenReturn(TEST_APP_NAME);
        when(mMockPackageManager.getApplicationInfo(eq(TEST_APP_NAME), anyInt()))
@@ -230,7 +215,6 @@ public class HintManagerServiceTest {
        when(mIPowerMock.getInterfaceVersion()).thenReturn(6);
        when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo);
        when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig);
        when(mIPowerMock.getSupportInfo()).thenReturn(mSupportInfo);
        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
        LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock);
    }
@@ -425,11 +409,8 @@ public class HintManagerServiceTest {
        HintManagerService service = createService();
        IBinder token = new Binder();

        IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
                .registerClient(mClientCallback);

        final int threadCount = data.maxGraphicsPipelineThreads;

        final int threadCount =
                service.getBinderServiceInstance().getMaxGraphicsPipelineThreadsCount();
        long sessionPtr1 = 1111L;
        long sessionId1 = 11111L;
        CountDownLatch stopLatch1 = new CountDownLatch(1);
@@ -1419,67 +1400,4 @@ public class HintManagerServiceTest {
        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1));
        verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2));
    }

    @Test
    public void testRegisteringClient() throws Exception {
        HintManagerService service = createService();
        IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
                .registerClient(mClientCallback);
        assertNotNull(data);
        assertEquals(data.supportInfo, mSupportInfo);
    }

    @Test
    public void testRegisteringClientOnV4() throws Exception {
        when(mIPowerMock.getInterfaceVersion()).thenReturn(4);
        HintManagerService service = createService();
        IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
                .registerClient(mClientCallback);
        assertNotNull(data);
        assertEquals(data.supportInfo.usesSessions, true);
        assertEquals(data.supportInfo.boosts, 0);
        assertEquals(data.supportInfo.modes, 0);
        assertEquals(data.supportInfo.sessionHints, 31);
        assertEquals(data.supportInfo.sessionModes, 0);
        assertEquals(data.supportInfo.sessionTags, 0);
        assertEquals(data.powerHalVersion, 4);
        assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE);
    }

    @Test
    public void testRegisteringClientOnV5() throws Exception {
        when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
        HintManagerService service = createService();
        IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
                .registerClient(mClientCallback);
        assertNotNull(data);
        assertEquals(data.supportInfo.usesSessions, true);
        assertEquals(data.supportInfo.boosts, 0);
        assertEquals(data.supportInfo.modes, 0);
        assertEquals(data.supportInfo.sessionHints, 255);
        assertEquals(data.supportInfo.sessionModes, 1);
        assertEquals(data.supportInfo.sessionTags, 31);
        assertEquals(data.powerHalVersion, 5);
        assertEquals(data.preferredRateNanos, DEFAULT_HINT_PREFERRED_RATE);
    }

    @Test
    public void testSettingUpOldClientWhenUnsupported() throws Exception {
        when(mIPowerMock.getInterfaceVersion()).thenReturn(5);
        // Mock unsupported to modify the default support behavior
        when(mNativeWrapperMock.halGetHintSessionPreferredRate())
                .thenReturn(-1L);
        HintManagerService service = createService();
        IHintManager.HintManagerClientData data = service.getBinderServiceInstance()
                .registerClient(mClientCallback);
        assertNotNull(data);
        assertEquals(data.supportInfo.usesSessions, false);
        assertEquals(data.supportInfo.boosts, 0);
        assertEquals(data.supportInfo.modes, 0);
        assertEquals(data.supportInfo.sessionHints, 0);
        assertEquals(data.supportInfo.sessionModes, 0);
        assertEquals(data.supportInfo.sessionTags, 0);
        assertEquals(data.powerHalVersion, 5);
        assertEquals(data.preferredRateNanos, -1);
    }
}