1 /* 2 * Copyright (C) 2015 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 com.android.car; 18 19 import android.content.Context; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.PackageManager.NameNotFoundException; 22 import android.os.Binder; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.Looper; 26 import android.os.SystemClock; 27 import android.util.ArrayMap; 28 import android.util.Slog; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 35 /** Utility class */ 36 public final class CarServiceUtils { 37 38 private static final String TAG = CarLog.tagFor(CarServiceUtils.class); 39 /** Empty int array */ 40 public static final int[] EMPTY_INT_ARRAY = new int[0]; 41 42 private static final String PACKAGE_NOT_FOUND = "Package not found:"; 43 44 /** K: class name, V: HandlerThread */ 45 private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>(); 46 47 /** do not construct. static only */ CarServiceUtils()48 private CarServiceUtils() {}; 49 50 /** 51 * Check if package name passed belongs to UID for the current binder call. 52 * @param context 53 * @param packageName 54 */ assertPackageName(Context context, String packageName)55 public static void assertPackageName(Context context, String packageName) 56 throws IllegalArgumentException, SecurityException { 57 if (packageName == null) { 58 throw new IllegalArgumentException("Package name null"); 59 } 60 ApplicationInfo appInfo = null; 61 try { 62 appInfo = context.getPackageManager().getApplicationInfo(packageName, 63 0); 64 } catch (NameNotFoundException e) { 65 String msg = PACKAGE_NOT_FOUND + packageName; 66 Slog.w(CarLog.TAG_SERVICE, msg, e); 67 throw new SecurityException(msg, e); 68 } 69 if (appInfo == null) { 70 throw new SecurityException(PACKAGE_NOT_FOUND + packageName); 71 } 72 int uid = Binder.getCallingUid(); 73 if (uid != appInfo.uid) { 74 throw new SecurityException("Wrong package name:" + packageName + 75 ", The package does not belong to caller's uid:" + uid); 76 } 77 } 78 79 /** 80 * Execute a runnable on the main thread 81 * 82 * @param action The code to run on the main thread. 83 */ runOnMain(Runnable action)84 public static void runOnMain(Runnable action) { 85 runOnLooper(Looper.getMainLooper(), action); 86 } 87 88 /** 89 * Execute a runnable in the given looper 90 * @param looper Looper to run the action. 91 * @param action The code to run. 92 */ runOnLooper(Looper looper, Runnable action)93 public static void runOnLooper(Looper looper, Runnable action) { 94 new Handler(looper).post(action); 95 } 96 97 /** 98 * Execute a call on the application's main thread, blocking until it is 99 * complete. Useful for doing things that are not thread-safe, such as 100 * looking at or modifying the view hierarchy. 101 * 102 * @param action The code to run on the main thread. 103 */ runOnMainSync(Runnable action)104 public static void runOnMainSync(Runnable action) { 105 runOnLooperSync(Looper.getMainLooper(), action); 106 } 107 108 /** 109 * Execute a call on the given Looper thread, blocking until it is 110 * complete. 111 * 112 * @param looper Looper to run the action. 113 * @param action The code to run on the main thread. 114 */ runOnLooperSync(Looper looper, Runnable action)115 public static void runOnLooperSync(Looper looper, Runnable action) { 116 if (Looper.myLooper() == looper) { 117 // requested thread is the same as the current thread. call directly. 118 action.run(); 119 } else { 120 Handler handler = new Handler(looper); 121 SyncRunnable sr = new SyncRunnable(action); 122 handler.post(sr); 123 sr.waitForComplete(); 124 } 125 } 126 127 private static final class SyncRunnable implements Runnable { 128 private final Runnable mTarget; 129 private volatile boolean mComplete = false; 130 SyncRunnable(Runnable target)131 public SyncRunnable(Runnable target) { 132 mTarget = target; 133 } 134 135 @Override run()136 public void run() { 137 mTarget.run(); 138 synchronized (this) { 139 mComplete = true; 140 notifyAll(); 141 } 142 } 143 waitForComplete()144 public void waitForComplete() { 145 synchronized (this) { 146 while (!mComplete) { 147 try { 148 wait(); 149 } catch (InterruptedException e) { 150 } 151 } 152 } 153 } 154 } 155 toFloatArray(List<Float> list)156 public static float[] toFloatArray(List<Float> list) { 157 int size = list.size(); 158 float[] array = new float[size]; 159 for (int i = 0; i < size; ++i) { 160 array[i] = list.get(i); 161 } 162 return array; 163 } 164 toLongArray(List<Long> list)165 public static long[] toLongArray(List<Long> list) { 166 int size = list.size(); 167 long[] array = new long[size]; 168 for (int i = 0; i < size; ++i) { 169 array[i] = list.get(i); 170 } 171 return array; 172 } 173 toIntArray(List<Integer> list)174 public static int[] toIntArray(List<Integer> list) { 175 int size = list.size(); 176 int[] array = new int[size]; 177 for (int i = 0; i < size; ++i) { 178 array[i] = list.get(i); 179 } 180 return array; 181 } 182 toByteArray(List<Byte> list)183 public static byte[] toByteArray(List<Byte> list) { 184 int size = list.size(); 185 byte[] array = new byte[size]; 186 for (int i = 0; i < size; ++i) { 187 array[i] = list.get(i); 188 } 189 return array; 190 } 191 192 /** 193 * Returns delta between elapsed time to uptime = {@link SystemClock#elapsedRealtime()} - 194 * {@link SystemClock#uptimeMillis()}. Note that this value will be always >= 0. 195 */ getUptimeToElapsedTimeDeltaInMillis()196 public static long getUptimeToElapsedTimeDeltaInMillis() { 197 int retry = 0; 198 int max_retry = 2; // try only up to twice 199 while (true) { 200 long elapsed1 = SystemClock.elapsedRealtime(); 201 long uptime = SystemClock.uptimeMillis(); 202 long elapsed2 = SystemClock.elapsedRealtime(); 203 if (elapsed1 == elapsed2) { // avoid possible 1 ms fluctuation. 204 return elapsed1 - uptime; 205 } 206 retry++; 207 if (retry >= max_retry) { 208 return elapsed1 - uptime; 209 } 210 } 211 } 212 213 /** 214 * Gets a static instance of {@code HandlerThread} for the given {@code name}. If the thread 215 * does not exist, create one and start it before returning. 216 */ getHandlerThread(String name)217 public static HandlerThread getHandlerThread(String name) { 218 synchronized (sHandlerThreads) { 219 HandlerThread thread = sHandlerThreads.get(name); 220 if (thread == null || !thread.isAlive()) { 221 Slog.i(TAG, "Starting HandlerThread:" + name); 222 thread = new HandlerThread(name); 223 thread.start(); 224 sHandlerThreads.put(name, thread); 225 } 226 return thread; 227 } 228 } 229 230 /** 231 * Finishes all queued {@code Handler} tasks for {@code HandlerThread} created via 232 * {@link #getHandlerThread(String)}. This is useful only for testing. 233 */ 234 @VisibleForTesting finishAllHandlerTasks()235 public static void finishAllHandlerTasks() { 236 ArrayList<HandlerThread> threads; 237 synchronized (sHandlerThreads) { 238 threads = new ArrayList<>(sHandlerThreads.values()); 239 } 240 ArrayList<SyncRunnable> syncs = new ArrayList<>(threads.size()); 241 for (int i = 0; i < threads.size(); i++) { 242 Handler handler = new Handler(threads.get(i).getLooper()); 243 SyncRunnable sr = new SyncRunnable(() -> { }); 244 handler.post(sr); 245 syncs.add(sr); 246 } 247 for (int i = 0; i < syncs.size(); i++) { 248 syncs.get(i).waitForComplete(); 249 } 250 } 251 } 252