1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.os; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SystemService; 22 import android.content.Context; 23 24 import com.android.internal.util.Preconditions; 25 26 import java.io.Closeable; 27 28 /** The PerformanceHintManager allows apps to send performance hint to system. */ 29 @SystemService(Context.PERFORMANCE_HINT_SERVICE) 30 public final class PerformanceHintManager { 31 private final long mNativeManagerPtr; 32 33 /** @hide */ create()34 public static PerformanceHintManager create() throws ServiceManager.ServiceNotFoundException { 35 long nativeManagerPtr = nativeAcquireManager(); 36 if (nativeManagerPtr == 0) { 37 throw new ServiceManager.ServiceNotFoundException(Context.PERFORMANCE_HINT_SERVICE); 38 } 39 return new PerformanceHintManager(nativeManagerPtr); 40 } 41 PerformanceHintManager(long nativeManagerPtr)42 private PerformanceHintManager(long nativeManagerPtr) { 43 mNativeManagerPtr = nativeManagerPtr; 44 } 45 46 /** 47 * Creates a {@link Session} for the given set of threads and sets their initial target work 48 * duration. 49 * 50 * @param tids The list of threads to be associated with this session. They must be part of 51 * this process' thread group. 52 * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new 53 * session. 54 * @return the new session if it is supported on this device, null if hint session is not 55 * supported on this device. 56 */ 57 @Nullable createHintSession(@onNull int[] tids, long initialTargetWorkDurationNanos)58 public Session createHintSession(@NonNull int[] tids, long initialTargetWorkDurationNanos) { 59 Preconditions.checkNotNull(tids, "tids cannot be null"); 60 Preconditions.checkArgumentPositive(initialTargetWorkDurationNanos, 61 "the hint target duration should be positive."); 62 long nativeSessionPtr = nativeCreateSession(mNativeManagerPtr, tids, 63 initialTargetWorkDurationNanos); 64 if (nativeSessionPtr == 0) return null; 65 return new Session(nativeSessionPtr); 66 } 67 68 /** 69 * Get preferred update rate information for this device. 70 * 71 * @return the preferred update rate supported by device software. 72 */ getPreferredUpdateRateNanos()73 public long getPreferredUpdateRateNanos() { 74 return nativeGetPreferredUpdateRateNanos(mNativeManagerPtr); 75 } 76 77 /** 78 * A Session represents a group of threads with an inter-related workload such that hints for 79 * their performance should be considered as a unit. The threads in a given session should be 80 * long-life and not created or destroyed dynamically. 81 * 82 * <p>Each session is expected to have a periodic workload with a target duration for each 83 * cycle. The cycle duration is likely greater than the target work duration to allow other 84 * parts of the pipeline to run within the available budget. For example, a renderer thread may 85 * work at 60hz in order to produce frames at the display's frame but have a target work 86 * duration of only 6ms.</p> 87 * 88 * <p>Any call in this class will change its internal data, so you must do your own thread 89 * safety to protect from racing.</p> 90 * 91 * <p>Note that the target work duration can be {@link #updateTargetWorkDuration(long) updated} 92 * if workloads change.</p> 93 * 94 * <p>After each cycle of work, the client is expected to 95 * {@link #reportActualWorkDuration(long) report} the actual time taken to complete.</p> 96 * 97 * <p>All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.</p> 98 */ 99 public static class Session implements Closeable { 100 private long mNativeSessionPtr; 101 102 /** @hide */ Session(long nativeSessionPtr)103 public Session(long nativeSessionPtr) { 104 mNativeSessionPtr = nativeSessionPtr; 105 } 106 107 /** @hide */ 108 @Override finalize()109 protected void finalize() throws Throwable { 110 try { 111 close(); 112 } finally { 113 super.finalize(); 114 } 115 } 116 117 /** 118 * Updates this session's target duration for each cycle of work. 119 * 120 * @param targetDurationNanos the new desired duration in nanoseconds 121 */ updateTargetWorkDuration(long targetDurationNanos)122 public void updateTargetWorkDuration(long targetDurationNanos) { 123 Preconditions.checkArgumentPositive(targetDurationNanos, "the hint target duration" 124 + " should be positive."); 125 nativeUpdateTargetWorkDuration(mNativeSessionPtr, targetDurationNanos); 126 } 127 128 /** 129 * Reports the actual duration for the last cycle of work. 130 * 131 * <p>The system will attempt to adjust the core placement of the threads within the thread 132 * group and/or the frequency of the core on which they are run to bring the actual duration 133 * close to the target duration.</p> 134 * 135 * @param actualDurationNanos how long the thread group took to complete its last task in 136 * nanoseconds 137 */ reportActualWorkDuration(long actualDurationNanos)138 public void reportActualWorkDuration(long actualDurationNanos) { 139 Preconditions.checkArgumentPositive(actualDurationNanos, "the actual duration should" 140 + " be positive."); 141 nativeReportActualWorkDuration(mNativeSessionPtr, actualDurationNanos); 142 } 143 144 /** 145 * Ends the current hint session. 146 * 147 * <p>Once called, you should not call anything else on this object.</p> 148 */ close()149 public void close() { 150 if (mNativeSessionPtr != 0) { 151 nativeCloseSession(mNativeSessionPtr); 152 mNativeSessionPtr = 0; 153 } 154 } 155 } 156 nativeAcquireManager()157 private static native long nativeAcquireManager(); nativeGetPreferredUpdateRateNanos(long nativeManagerPtr)158 private static native long nativeGetPreferredUpdateRateNanos(long nativeManagerPtr); nativeCreateSession(long nativeManagerPtr, int[] tids, long initialTargetWorkDurationNanos)159 private static native long nativeCreateSession(long nativeManagerPtr, 160 int[] tids, long initialTargetWorkDurationNanos); nativeUpdateTargetWorkDuration(long nativeSessionPtr, long targetDurationNanos)161 private static native void nativeUpdateTargetWorkDuration(long nativeSessionPtr, 162 long targetDurationNanos); nativeReportActualWorkDuration(long nativeSessionPtr, long actualDurationNanos)163 private static native void nativeReportActualWorkDuration(long nativeSessionPtr, 164 long actualDurationNanos); nativeCloseSession(long nativeSessionPtr)165 private static native void nativeCloseSession(long nativeSessionPtr); 166 } 167