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

Commit 0b2ad9f7 authored by Bo Liu's avatar Bo Liu
Browse files

Implement java PerformanceHintManager on top of native

Note some exceptions became silence errors in this conversion.

Test: None
Bug: 194204196
Change-Id: Ia3cc7f2396f2e307a23b40b3f104a2fa90352196
parent 6a3fc60f
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -158,7 +158,6 @@ import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
import android.os.IDumpstate;
import android.os.IHardwarePropertiesManager;
import android.os.IHintManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
import android.os.ISystemUpdateManager;
@@ -600,10 +599,7 @@ public final class SystemServiceRegistry {
            @Override
            public PerformanceHintManager createService(ContextImpl ctx)
                    throws ServiceNotFoundException {
                IBinder hintBinder = ServiceManager.getServiceOrThrow(
                        Context.PERFORMANCE_HINT_SERVICE);
                IHintManager hintService = IHintManager.Stub.asInterface(hintBinder);
                return new PerformanceHintManager(hintService);
                return PerformanceHintManager.create();
            }});

        registerService(Context.RECOVERY_SERVICE, RecoverySystem.class,
+45 −105
Original line number Diff line number Diff line
@@ -24,24 +24,23 @@ import android.content.Context;
import com.android.internal.util.Preconditions;

import java.io.Closeable;
import java.util.ArrayList;

/** The PerformanceHintManager allows apps to send performance hint to system. */
@SystemService(Context.PERFORMANCE_HINT_SERVICE)
public final class PerformanceHintManager {
    private static final String TAG = "PerformanceHintManager";
    private final IHintManager mService;
    // HAL preferred update rate
    private final long mPreferredRate;
    private final long mNativeManagerPtr;

    /** @hide */
    public PerformanceHintManager(IHintManager service) {
        mService = service;
        try {
            mPreferredRate = mService.getHintSessionPreferredRate();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
    public static PerformanceHintManager create() throws ServiceManager.ServiceNotFoundException {
        long nativeManagerPtr = nativeAcquireManager();
        if (nativeManagerPtr == 0) {
            throw new ServiceManager.ServiceNotFoundException(Context.PERFORMANCE_HINT_SERVICE);
        }
        return new PerformanceHintManager(nativeManagerPtr);
    }

    private PerformanceHintManager(long nativeManagerPtr) {
        mNativeManagerPtr = nativeManagerPtr;
    }

    /**
@@ -57,16 +56,13 @@ public final class PerformanceHintManager {
     */
    @Nullable
    public Session createHintSession(@NonNull int[] tids, long initialTargetWorkDurationNanos) {
        try {
            IBinder token = new Binder();
            IHintSession session = mService.createHintSession(token, tids,
        Preconditions.checkNotNull(tids, "tids cannot be null");
        Preconditions.checkArgumentPositive(initialTargetWorkDurationNanos,
                "the hint target duration should be positive.");
        long nativeSessionPtr = nativeCreateSession(mNativeManagerPtr, tids,
                initialTargetWorkDurationNanos);
            if (session == null) return null;
            return new Session(session, sNanoClock, mPreferredRate,
                    initialTargetWorkDurationNanos);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        if (nativeSessionPtr == 0) return null;
        return new Session(nativeSessionPtr);
    }

    /**
@@ -75,7 +71,7 @@ public final class PerformanceHintManager {
     * @return the preferred update rate supported by device software.
     */
    public long getPreferredUpdateRateNanos() {
        return mPreferredRate;
        return nativeGetPreferredUpdateRateNanos(mNativeManagerPtr);
    }

    /**
@@ -101,28 +97,21 @@ public final class PerformanceHintManager {
     * <p>All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.</p>
     */
    public static class Session implements Closeable {
        private final IHintSession mSession;
        private final NanoClock mElapsedRealtimeClock;
        // Target duration for choosing update rate
        private long mTargetDurationInNanos;
        // HAL preferred update rate
        private long mPreferredRate;
        // Last update timestamp
        private long mLastUpdateTimeStamp = -1L;
        // Cached samples
        private final ArrayList<Long> mActualDurationNanos;
        private final ArrayList<Long> mTimeStampNanos;
        private long mNativeSessionPtr;

        /** @hide */
        public Session(IHintSession session, NanoClock elapsedRealtimeClock, long preferredRate,
                long durationNanos) {
            mSession = session;
            mElapsedRealtimeClock = elapsedRealtimeClock;
            mTargetDurationInNanos = durationNanos;
            mPreferredRate = preferredRate;
            mActualDurationNanos = new ArrayList<Long>();
            mTimeStampNanos = new ArrayList<Long>();
            mLastUpdateTimeStamp = mElapsedRealtimeClock.nanos();
        public Session(long nativeSessionPtr) {
            mNativeSessionPtr = nativeSessionPtr;
        }

        /** @hide */
        @Override
        protected void finalize() throws Throwable {
            try {
                close();
            } finally {
                super.finalize();
            }
        }

        /**
@@ -133,19 +122,7 @@ public final class PerformanceHintManager {
        public void updateTargetWorkDuration(long targetDurationNanos) {
            Preconditions.checkArgumentPositive(targetDurationNanos, "the hint target duration"
                    + " should be positive.");
            try {
                mSession.updateTargetWorkDuration(targetDurationNanos);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            mTargetDurationInNanos = targetDurationNanos;
            /**
             * Most of the workload is target_duration dependent, so now clear the cached samples
             * as they are most likely obsolete.
             */
            mActualDurationNanos.clear();
            mTimeStampNanos.clear();
            mLastUpdateTimeStamp = mElapsedRealtimeClock.nanos();
            nativeUpdateTargetWorkDuration(mNativeSessionPtr, targetDurationNanos);
        }

        /**
@@ -161,38 +138,7 @@ public final class PerformanceHintManager {
        public void reportActualWorkDuration(long actualDurationNanos) {
            Preconditions.checkArgumentPositive(actualDurationNanos, "the actual duration should"
                    + " be positive.");
            final long now = mElapsedRealtimeClock.nanos();
            mActualDurationNanos.add(actualDurationNanos);
            mTimeStampNanos.add(now);

            /**
             * Use current sample to determine the rate limit. We can pick a shorter rate limit
             * if any sample underperformed, however, it could be the lower level system is slow
             * to react. So here we explicitly choose the rate limit with the latest sample.
             */
            long rateLimit =
                    actualDurationNanos > mTargetDurationInNanos ? mPreferredRate
                            : 10 * mPreferredRate;

            if (now - mLastUpdateTimeStamp <= rateLimit) {
                return;
            }
            Preconditions.checkState(mActualDurationNanos.size() == mTimeStampNanos.size());
            final int size = mActualDurationNanos.size();
            long[] actualDurationArray = new long[size];
            long[] timeStampArray = new long[size];
            for (int i = 0; i < size; i++) {
                actualDurationArray[i] = mActualDurationNanos.get(i);
                timeStampArray[i] = mTimeStampNanos.get(i);
            }
            try {
                mSession.reportActualWorkDuration(actualDurationArray, timeStampArray);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            mActualDurationNanos.clear();
            mTimeStampNanos.clear();
            mLastUpdateTimeStamp = now;
            nativeReportActualWorkDuration(mNativeSessionPtr, actualDurationNanos);
        }

        /**
@@ -201,26 +147,20 @@ public final class PerformanceHintManager {
         * <p>Once called, you should not call anything else on this object.</p>
         */
        public void close() {
            try {
                mSession.close();
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            if (mNativeSessionPtr != 0) {
                nativeCloseSession(mNativeSessionPtr);
                mNativeSessionPtr = 0;
            }
        }
    }

    /**
     * The interface is to make the FakeClock for testing.
     * @hide
     */
    public interface NanoClock {
        /** Gets the current nanosecond instant of the clock. */
        long nanos();
    }

    private static final NanoClock sNanoClock = new NanoClock() {
        public long nanos() {
            return SystemClock.elapsedRealtimeNanos();
        }
    };
    private static native long nativeAcquireManager();
    private static native long nativeGetPreferredUpdateRateNanos(long nativeManagerPtr);
    private static native long nativeCreateSession(long nativeManagerPtr,
            int[] tids, long initialTargetWorkDurationNanos);
    private static native void nativeUpdateTargetWorkDuration(long nativeSessionPtr,
            long targetDurationNanos);
    private static native void nativeReportActualWorkDuration(long nativeSessionPtr,
            long actualDurationNanos);
    private static native void nativeCloseSession(long nativeSessionPtr);
}
+1 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ cc_library_shared {
                "android_os_MemoryFile.cpp",
                "android_os_MessageQueue.cpp",
                "android_os_Parcel.cpp",
                "android_os_PerformanceHintManager.cpp",
                "android_os_SELinux.cpp",
                "android_os_ServiceManager.cpp",
                "android_os_SharedMemory.cpp",
+2 −0
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ extern int register_android_os_NativeHandle(JNIEnv *env);
extern int register_android_os_ServiceManager(JNIEnv *env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
extern int register_android_os_PerformanceHintManager(JNIEnv* env);
extern int register_android_os_SELinux(JNIEnv* env);
extern int register_android_os_VintfObject(JNIEnv *env);
extern int register_android_os_VintfRuntimeInfo(JNIEnv *env);
@@ -1518,6 +1519,7 @@ static const RegJNIRec gRegJNI[] = {
        REG_JNI(register_android_os_SystemProperties),
        REG_JNI(register_android_os_Binder),
        REG_JNI(register_android_os_Parcel),
        REG_JNI(register_android_os_PerformanceHintManager),
        REG_JNI(register_android_os_HidlMemory),
        REG_JNI(register_android_os_HidlSupport),
        REG_JNI(register_android_os_HwBinder),
+155 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "PerfHint-jni"

#include "jni.h"

#include <dlfcn.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedPrimitiveArray.h>
#include <utils/Log.h>
#include <vector>

#include "core_jni_helpers.h"

namespace android {

namespace {

struct APerformanceHintManager;
struct APerformanceHintSession;

typedef APerformanceHintManager* (*APH_getManager)();
typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
                                                      size_t, int64_t);
typedef int64_t (*APH_getPreferredUpdateRateNanos)(APerformanceHintManager* manager);
typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
typedef void (*APH_closeSession)(APerformanceHintSession* session);

bool gAPerformanceHintBindingInitialized = false;
APH_getManager gAPH_getManagerFn = nullptr;
APH_createSession gAPH_createSessionFn = nullptr;
APH_getPreferredUpdateRateNanos gAPH_getPreferredUpdateRateNanosFn = nullptr;
APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
APH_closeSession gAPH_closeSessionFn = nullptr;

void ensureAPerformanceHintBindingInitialized() {
    if (gAPerformanceHintBindingInitialized) return;

    void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
    LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");

    gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
    LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
                        "Failed to find required symbol APerformanceHint_getManager!");

    gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
    LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
                        "Failed to find required symbol APerformanceHint_createSession!");

    gAPH_getPreferredUpdateRateNanosFn =
            (APH_getPreferredUpdateRateNanos)dlsym(handle_,
                                                   "APerformanceHint_getPreferredUpdateRateNanos");
    LOG_ALWAYS_FATAL_IF(gAPH_getPreferredUpdateRateNanosFn == nullptr,
                        "Failed to find required symbol "
                        "APerformanceHint_getPreferredUpdateRateNanos!");

    gAPH_updateTargetWorkDurationFn =
            (APH_updateTargetWorkDuration)dlsym(handle_,
                                                "APerformanceHint_updateTargetWorkDuration");
    LOG_ALWAYS_FATAL_IF(gAPH_updateTargetWorkDurationFn == nullptr,
                        "Failed to find required symbol "
                        "APerformanceHint_updateTargetWorkDuration!");

    gAPH_reportActualWorkDurationFn =
            (APH_reportActualWorkDuration)dlsym(handle_,
                                                "APerformanceHint_reportActualWorkDuration");
    LOG_ALWAYS_FATAL_IF(gAPH_reportActualWorkDurationFn == nullptr,
                        "Failed to find required symbol "
                        "APerformanceHint_reportActualWorkDuration!");

    gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
    LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
                        "Failed to find required symbol APerformanceHint_closeSession!");

    gAPerformanceHintBindingInitialized = true;
}

} // namespace

static jlong nativeAcquireManager(JNIEnv* env, jclass clazz) {
    ensureAPerformanceHintBindingInitialized();
    return reinterpret_cast<jlong>(gAPH_getManagerFn());
}

static jlong nativeGetPreferredUpdateRateNanos(JNIEnv* env, jclass clazz, jlong nativeManagerPtr) {
    ensureAPerformanceHintBindingInitialized();
    return gAPH_getPreferredUpdateRateNanosFn(
            reinterpret_cast<APerformanceHintManager*>(nativeManagerPtr));
}

static jlong nativeCreateSession(JNIEnv* env, jclass clazz, jlong nativeManagerPtr, jintArray tids,
                                 jlong initialTargetWorkDurationNanos) {
    ensureAPerformanceHintBindingInitialized();
    if (tids == nullptr) return 0;
    std::vector<int32_t> tidsVector;
    ScopedIntArrayRO tidsArray(env, tids);
    for (size_t i = 0; i < tidsArray.size(); ++i) {
        tidsVector.push_back(static_cast<int32_t>(tidsArray[i]));
    }
    return reinterpret_cast<jlong>(
            gAPH_createSessionFn(reinterpret_cast<APerformanceHintManager*>(nativeManagerPtr),
                                 tidsVector.data(), tidsVector.size(),
                                 initialTargetWorkDurationNanos));
}

static void nativeUpdateTargetWorkDuration(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
                                           jlong targetDurationNanos) {
    ensureAPerformanceHintBindingInitialized();
    gAPH_updateTargetWorkDurationFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
                                    targetDurationNanos);
}

static void nativeReportActualWorkDuration(JNIEnv* env, jclass clazz, jlong nativeSessionPtr,
                                           jlong actualDurationNanos) {
    ensureAPerformanceHintBindingInitialized();
    gAPH_reportActualWorkDurationFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr),
                                    actualDurationNanos);
}

static void nativeCloseSession(JNIEnv* env, jclass clazz, jlong nativeSessionPtr) {
    ensureAPerformanceHintBindingInitialized();
    gAPH_closeSessionFn(reinterpret_cast<APerformanceHintSession*>(nativeSessionPtr));
}

static const JNINativeMethod gPerformanceHintMethods[] = {
        {"nativeAcquireManager", "()J", (void*)nativeAcquireManager},
        {"nativeGetPreferredUpdateRateNanos", "(J)J", (void*)nativeGetPreferredUpdateRateNanos},
        {"nativeCreateSession", "(J[IJ)J", (void*)nativeCreateSession},
        {"nativeUpdateTargetWorkDuration", "(JJ)V", (void*)nativeUpdateTargetWorkDuration},
        {"nativeReportActualWorkDuration", "(JJ)V", (void*)nativeReportActualWorkDuration},
        {"nativeCloseSession", "(J)V", (void*)nativeCloseSession},
};

int register_android_os_PerformanceHintManager(JNIEnv* env) {
    return RegisterMethodsOrDie(env, "android/os/PerformanceHintManager", gPerformanceHintMethods,
                                NELEM(gPerformanceHintMethods));
}

} // namespace android
Loading