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.car.Car; 20 import android.car.builtin.util.Slogf; 21 import android.content.Context; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.PackageManager; 24 import android.content.pm.PackageManager.NameNotFoundException; 25 import android.hardware.automotive.vehicle.SubscribeOptions; 26 import android.os.Binder; 27 import android.os.Handler; 28 import android.os.HandlerThread; 29 import android.os.Looper; 30 import android.os.Process; 31 import android.os.SystemClock; 32 import android.util.ArrayMap; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 36 import java.util.ArrayList; 37 import java.util.Arrays; 38 import java.util.List; 39 40 /** Utility class */ 41 public final class CarServiceUtils { 42 43 private static final String TAG = CarLog.tagFor(CarServiceUtils.class); 44 /** Empty int array */ 45 public static final int[] EMPTY_INT_ARRAY = new int[0]; 46 private static final String COMMON_HANDLER_THREAD_NAME = 47 "CarServiceUtils_COMMON_HANDLER_THREAD"; 48 49 private static final String PACKAGE_NOT_FOUND = "Package not found:"; 50 51 /** K: class name, V: HandlerThread */ 52 private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>(); 53 54 /** do not construct. static only */ CarServiceUtils()55 private CarServiceUtils() {} 56 57 /** 58 * Check if package name passed belongs to UID for the current binder call. 59 * @param context 60 * @param packageName 61 */ assertPackageName(Context context, String packageName)62 public static void assertPackageName(Context context, String packageName) 63 throws IllegalArgumentException, SecurityException { 64 if (packageName == null) { 65 throw new IllegalArgumentException("Package name null"); 66 } 67 ApplicationInfo appInfo = null; 68 try { 69 appInfo = context.getPackageManager().getApplicationInfo(packageName, 70 0); 71 } catch (NameNotFoundException e) { 72 String msg = PACKAGE_NOT_FOUND + packageName; 73 Slogf.w(CarLog.TAG_SERVICE, msg, e); 74 throw new SecurityException(msg, e); 75 } 76 if (appInfo == null) { 77 throw new SecurityException(PACKAGE_NOT_FOUND + packageName); 78 } 79 int uid = Binder.getCallingUid(); 80 if (uid != appInfo.uid) { 81 throw new SecurityException("Wrong package name:" + packageName + 82 ", The package does not belong to caller's uid:" + uid); 83 } 84 } 85 86 /** 87 * Execute a runnable on the main thread 88 * 89 * @param action The code to run on the main thread. 90 */ runOnMain(Runnable action)91 public static void runOnMain(Runnable action) { 92 runOnLooper(Looper.getMainLooper(), action); 93 } 94 95 /** 96 * Execute a runnable in the given looper 97 * @param looper Looper to run the action. 98 * @param action The code to run. 99 */ runOnLooper(Looper looper, Runnable action)100 public static void runOnLooper(Looper looper, Runnable action) { 101 new Handler(looper).post(action); 102 } 103 104 /** 105 * Execute a call on the application's main thread, blocking until it is 106 * complete. Useful for doing things that are not thread-safe, such as 107 * looking at or modifying the view hierarchy. 108 * 109 * @param action The code to run on the main thread. 110 */ runOnMainSync(Runnable action)111 public static void runOnMainSync(Runnable action) { 112 runOnLooperSync(Looper.getMainLooper(), action); 113 } 114 115 /** 116 * Execute a delayed call on the application's main thread, blocking until it is 117 * complete. See {@link #runOnMainSync(Runnable)} 118 * 119 * @param action The code to run on the main thread. 120 * @param delayMillis The delay (in milliseconds) until the Runnable will be executed. 121 */ runOnMainSyncDelayed(Runnable action, long delayMillis)122 public static void runOnMainSyncDelayed(Runnable action, long delayMillis) { 123 runOnLooperSyncDelayed(Looper.getMainLooper(), action, delayMillis); 124 } 125 126 /** 127 * Execute a call on the given Looper thread, blocking until it is 128 * complete. 129 * 130 * @param looper Looper to run the action. 131 * @param action The code to run on the looper thread. 132 */ runOnLooperSync(Looper looper, Runnable action)133 public static void runOnLooperSync(Looper looper, Runnable action) { 134 runOnLooperSyncDelayed(looper, action, /* delayMillis */ 0L); 135 } 136 137 /** 138 * Executes a delayed call on the given Looper thread, blocking until it is complete. 139 * 140 * @param looper Looper to run the action. 141 * @param action The code to run on the looper thread. 142 * @param delayMillis The delay (in milliseconds) until the Runnable will be executed. 143 */ runOnLooperSyncDelayed(Looper looper, Runnable action, long delayMillis)144 public static void runOnLooperSyncDelayed(Looper looper, Runnable action, long delayMillis) { 145 if (Looper.myLooper() == looper) { 146 // requested thread is the same as the current thread. call directly. 147 action.run(); 148 } else { 149 Handler handler = new Handler(looper); 150 SyncRunnable sr = new SyncRunnable(action); 151 handler.postDelayed(sr, delayMillis); 152 sr.waitForComplete(); 153 } 154 } 155 156 /** 157 * Executes a runnable on the common thread. Useful for doing any kind of asynchronous work 158 * across the car related code that doesn't need to be on the main thread. 159 * 160 * @param action The code to run on the common thread. 161 */ runOnCommon(Runnable action)162 public static void runOnCommon(Runnable action) { 163 runOnLooper(getCommonHandlerThread().getLooper(), action); 164 } 165 166 private static final class SyncRunnable implements Runnable { 167 private final Runnable mTarget; 168 private volatile boolean mComplete = false; 169 SyncRunnable(Runnable target)170 public SyncRunnable(Runnable target) { 171 mTarget = target; 172 } 173 174 @Override run()175 public void run() { 176 mTarget.run(); 177 synchronized (this) { 178 mComplete = true; 179 notifyAll(); 180 } 181 } 182 waitForComplete()183 public void waitForComplete() { 184 synchronized (this) { 185 while (!mComplete) { 186 try { 187 wait(); 188 } catch (InterruptedException e) { 189 } 190 } 191 } 192 } 193 } 194 toFloatArray(List<Float> list)195 public static float[] toFloatArray(List<Float> list) { 196 int size = list.size(); 197 float[] array = new float[size]; 198 for (int i = 0; i < size; ++i) { 199 array[i] = list.get(i); 200 } 201 return array; 202 } 203 toLongArray(List<Long> list)204 public static long[] toLongArray(List<Long> list) { 205 int size = list.size(); 206 long[] array = new long[size]; 207 for (int i = 0; i < size; ++i) { 208 array[i] = list.get(i); 209 } 210 return array; 211 } 212 toIntArray(List<Integer> list)213 public static int[] toIntArray(List<Integer> list) { 214 int size = list.size(); 215 int[] array = new int[size]; 216 for (int i = 0; i < size; ++i) { 217 array[i] = list.get(i); 218 } 219 return array; 220 } 221 toByteArray(List<Byte> list)222 public static byte[] toByteArray(List<Byte> list) { 223 int size = list.size(); 224 byte[] array = new byte[size]; 225 for (int i = 0; i < size; ++i) { 226 array[i] = list.get(i); 227 } 228 return array; 229 } 230 231 /** 232 * Returns delta between elapsed time to uptime = {@link SystemClock#elapsedRealtime()} - 233 * {@link SystemClock#uptimeMillis()}. Note that this value will be always >= 0. 234 */ getUptimeToElapsedTimeDeltaInMillis()235 public static long getUptimeToElapsedTimeDeltaInMillis() { 236 int retry = 0; 237 int max_retry = 2; // try only up to twice 238 while (true) { 239 long elapsed1 = SystemClock.elapsedRealtime(); 240 long uptime = SystemClock.uptimeMillis(); 241 long elapsed2 = SystemClock.elapsedRealtime(); 242 if (elapsed1 == elapsed2) { // avoid possible 1 ms fluctuation. 243 return elapsed1 - uptime; 244 } 245 retry++; 246 if (retry >= max_retry) { 247 return elapsed1 - uptime; 248 } 249 } 250 } 251 252 /** 253 * Gets a static instance of {@code HandlerThread} for the given {@code name}. If the thread 254 * does not exist, create one and start it before returning. 255 */ getHandlerThread(String name)256 public static HandlerThread getHandlerThread(String name) { 257 synchronized (sHandlerThreads) { 258 HandlerThread thread = sHandlerThreads.get(name); 259 if (thread == null || !thread.isAlive()) { 260 Slogf.i(TAG, "Starting HandlerThread:" + name); 261 thread = new HandlerThread(name); 262 thread.start(); 263 sHandlerThreads.put(name, thread); 264 } 265 return thread; 266 } 267 } 268 269 /** 270 * Gets the static instance of the common {@code HandlerThread} meant to be used across 271 * CarService. 272 */ getCommonHandlerThread()273 public static HandlerThread getCommonHandlerThread() { 274 return getHandlerThread(COMMON_HANDLER_THREAD_NAME); 275 } 276 277 /** 278 * Finishes all queued {@code Handler} tasks for {@code HandlerThread} created via 279 * {@link#getHandlerThread(String)}. This is useful only for testing. 280 */ 281 @VisibleForTesting finishAllHandlerTasks()282 public static void finishAllHandlerTasks() { 283 ArrayList<HandlerThread> threads; 284 synchronized (sHandlerThreads) { 285 threads = new ArrayList<>(sHandlerThreads.values()); 286 } 287 ArrayList<SyncRunnable> syncs = new ArrayList<>(threads.size()); 288 for (int i = 0; i < threads.size(); i++) { 289 if (!threads.get(i).isAlive()) { 290 continue; 291 } 292 Handler handler = new Handler(threads.get(i).getLooper()); 293 SyncRunnable sr = new SyncRunnable(() -> { }); 294 if (handler.post(sr)) { 295 // Track the threads only where SyncRunnable is posted successfully. 296 syncs.add(sr); 297 } 298 } 299 for (int i = 0; i < syncs.size(); i++) { 300 syncs.get(i).waitForComplete(); 301 } 302 } 303 304 /** 305 * Assert if binder call is coming from system process like system server or if it is called 306 * from its own process even if it is not system. The latter can happen in test environment. 307 * Note that car service runs as system user but test like car service test will not. 308 */ assertCallingFromSystemProcessOrSelf()309 public static void assertCallingFromSystemProcessOrSelf() { 310 if (isCallingFromSystemProcessOrSelf()) { 311 throw new SecurityException("Only allowed from system or self"); 312 } 313 } 314 315 /** 316 * @return true if binder call is coming from system process like system server or if it is 317 * called from its own process even if it is not system. 318 */ isCallingFromSystemProcessOrSelf()319 public static boolean isCallingFromSystemProcessOrSelf() { 320 int uid = Binder.getCallingUid(); 321 int pid = Binder.getCallingPid(); 322 return uid != Process.SYSTEM_UID && pid != Process.myPid(); 323 } 324 325 326 /** Utility for checking permission */ assertVehicleHalMockPermission(Context context)327 public static void assertVehicleHalMockPermission(Context context) { 328 assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL); 329 } 330 331 /** Utility for checking permission */ assertNavigationManagerPermission(Context context)332 public static void assertNavigationManagerPermission(Context context) { 333 assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER); 334 } 335 336 /** Utility for checking permission */ assertClusterManagerPermission(Context context)337 public static void assertClusterManagerPermission(Context context) { 338 assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL); 339 } 340 341 /** Utility for checking permission */ assertPowerPermission(Context context)342 public static void assertPowerPermission(Context context) { 343 assertPermission(context, Car.PERMISSION_CAR_POWER); 344 } 345 346 /** Utility for checking permission */ assertProjectionPermission(Context context)347 public static void assertProjectionPermission(Context context) { 348 assertPermission(context, Car.PERMISSION_CAR_PROJECTION); 349 } 350 351 /** Verify the calling context has the {@link Car#PERMISSION_CAR_PROJECTION_STATUS} */ assertProjectionStatusPermission(Context context)352 public static void assertProjectionStatusPermission(Context context) { 353 assertPermission(context, Car.PERMISSION_CAR_PROJECTION_STATUS); 354 } 355 356 /** Utility for checking permission */ assertAnyDiagnosticPermission(Context context)357 public static void assertAnyDiagnosticPermission(Context context) { 358 assertAnyPermission(context, 359 Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL, 360 Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR); 361 } 362 363 /** Utility for checking permission */ assertDrivingStatePermission(Context context)364 public static void assertDrivingStatePermission(Context context) { 365 assertPermission(context, Car.PERMISSION_CAR_DRIVING_STATE); 366 } 367 368 /** 369 * Verify the calling context has either {@link Car#PERMISSION_VMS_SUBSCRIBER} or 370 * {@link Car#PERMISSION_VMS_PUBLISHER} 371 */ assertAnyVmsPermission(Context context)372 public static void assertAnyVmsPermission(Context context) { 373 assertAnyPermission(context, 374 Car.PERMISSION_VMS_SUBSCRIBER, 375 Car.PERMISSION_VMS_PUBLISHER); 376 } 377 378 /** Utility for checking permission */ assertVmsPublisherPermission(Context context)379 public static void assertVmsPublisherPermission(Context context) { 380 assertPermission(context, Car.PERMISSION_VMS_PUBLISHER); 381 } 382 383 /** Utility for checking permission */ assertVmsSubscriberPermission(Context context)384 public static void assertVmsSubscriberPermission(Context context) { 385 assertPermission(context, Car.PERMISSION_VMS_SUBSCRIBER); 386 } 387 388 /** Utility for checking permission */ assertPermission(Context context, String permission)389 public static void assertPermission(Context context, String permission) { 390 if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { 391 throw new SecurityException("requires " + permission); 392 } 393 } 394 395 /** 396 * Checks to see if the caller has a permission. 397 * 398 * @return boolean TRUE if caller has the permission. 399 */ hasPermission(Context context, String permission)400 public static boolean hasPermission(Context context, String permission) { 401 return context.checkCallingOrSelfPermission(permission) 402 == PackageManager.PERMISSION_GRANTED; 403 } 404 405 /** Utility for checking permission */ assertAnyPermission(Context context, String... permissions)406 public static void assertAnyPermission(Context context, String... permissions) { 407 for (String permission : permissions) { 408 if (context.checkCallingOrSelfPermission(permission) 409 == PackageManager.PERMISSION_GRANTED) { 410 return; 411 } 412 } 413 throw new SecurityException("requires any of " + Arrays.toString(permissions)); 414 } 415 416 /** 417 * Turns a {@code SubscribeOptions} to {@code 418 * android.hardware.automotive.vehicle.V2_0.SubscribeOptions} 419 */ subscribeOptionsToHidl( SubscribeOptions options)420 public static android.hardware.automotive.vehicle.V2_0.SubscribeOptions subscribeOptionsToHidl( 421 SubscribeOptions options) { 422 android.hardware.automotive.vehicle.V2_0.SubscribeOptions hidlOptions = 423 new android.hardware.automotive.vehicle.V2_0.SubscribeOptions(); 424 hidlOptions.propId = options.propId; 425 hidlOptions.sampleRate = options.sampleRate; 426 // HIDL backend requires flags to be set although it is not used any more. 427 hidlOptions.flags = android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR; 428 // HIDL backend does not support area IDs, so we ignore options.areaId field. 429 return hidlOptions; 430 } 431 } 432