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

Commit 9533a3db authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge changes from topic "native_hint" into sc-dev am: ea52c875

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15326475

Change-Id: I9e341b02a701d6a20ce8b60cacfc647beae219b2
parents 4333a837 ea52c875
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