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 static android.car.user.CarUserManager.lifecycleEventTypeToString; 20 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 21 import static android.os.Process.INVALID_UID; 22 23 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.SuppressLint; 28 import android.annotation.UserIdInt; 29 import android.app.ActivityManager; 30 import android.app.ActivityOptions; 31 import android.car.Car; 32 import android.car.builtin.content.ContextHelper; 33 import android.car.builtin.content.pm.PackageManagerHelper; 34 import android.car.builtin.os.UserManagerHelper; 35 import android.car.builtin.util.Slogf; 36 import android.car.user.CarUserManager.UserLifecycleEvent; 37 import android.content.ComponentName; 38 import android.content.ContentResolver; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.ServiceConnection; 42 import android.content.pm.PackageManager; 43 import android.hardware.automotive.vehicle.SubscribeOptions; 44 import android.net.Uri; 45 import android.os.Binder; 46 import android.os.Handler; 47 import android.os.HandlerThread; 48 import android.os.IBinder; 49 import android.os.Looper; 50 import android.os.Process; 51 import android.os.SystemClock; 52 import android.os.UserHandle; 53 import android.os.UserManager; 54 import android.security.keystore.KeyGenParameterSpec; 55 import android.security.keystore.KeyProperties; 56 import android.util.ArrayMap; 57 import android.util.ArraySet; 58 import android.util.Log; 59 60 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 61 import com.android.car.internal.common.CommonConstants.UserLifecycleEventType; 62 import com.android.internal.annotations.VisibleForTesting; 63 import com.android.internal.util.Preconditions; 64 65 import java.io.ByteArrayOutputStream; 66 import java.io.IOException; 67 import java.nio.ByteBuffer; 68 import java.nio.ByteOrder; 69 import java.security.KeyStore; 70 import java.security.KeyStore.SecretKeyEntry; 71 import java.util.ArrayList; 72 import java.util.Arrays; 73 import java.util.List; 74 import java.util.Objects; 75 import java.util.StringJoiner; 76 import java.util.UUID; 77 import java.util.concurrent.ThreadLocalRandom; 78 79 import javax.crypto.Cipher; 80 import javax.crypto.KeyGenerator; 81 import javax.crypto.SecretKey; 82 import javax.crypto.spec.GCMParameterSpec; 83 84 /** Utility class */ 85 public final class CarServiceUtils { 86 87 // https://developer.android.com/reference/java/util/UUID 88 private static final int UUID_LENGTH = 16; 89 private static final String TAG = CarLog.tagFor(CarServiceUtils.class); 90 private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG); 91 92 private static final String COMMON_HANDLER_THREAD_NAME = 93 "CarServiceUtils_COMMON_HANDLER_THREAD"; 94 private static final byte[] CHAR_POOL_FOR_RANDOM_STRING = 95 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes(); 96 97 private static final String PACKAGE_NOT_FOUND = "Package not found:"; 98 private static final String ANDROID_KEYSTORE_NAME = "AndroidKeyStore"; 99 private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; 100 private static final int GCM_TAG_LENGTH = 128; 101 102 /** K: class name, V: HandlerThread */ 103 private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>(); 104 105 @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE, 106 details = "private constructor") CarServiceUtils()107 private CarServiceUtils() { 108 throw new UnsupportedOperationException("contains only static methods"); 109 } 110 111 /** 112 * Returns a byte buffer corresponding to the passed long argument. 113 * 114 * @param primitive data to convert format. 115 */ longToBytes(long primitive)116 public static byte[] longToBytes(long primitive) { 117 ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); 118 buffer.putLong(primitive); 119 return buffer.array(); 120 } 121 122 /** 123 * Returns a byte buffer corresponding to the passed long argument. 124 * 125 * @param array data to convert format. 126 */ bytesToLong(byte[] array)127 public static long bytesToLong(byte[] array) { 128 ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE); 129 buffer.put(array); 130 buffer.flip(); 131 long value = buffer.getLong(); 132 return value; 133 } 134 135 /** 136 * Returns a String in Hex format that is formed from the bytes in the byte array 137 * Useful for debugging 138 * 139 * @param array the byte array 140 * @return the Hex string version of the input byte array 141 */ byteArrayToHexString(byte[] array)142 public static String byteArrayToHexString(byte[] array) { 143 StringBuilder sb = new StringBuilder(array.length * 2); 144 for (byte b : array) { 145 sb.append(String.format("%02x", b)); 146 } 147 return sb.toString(); 148 } 149 150 /** 151 * Convert UUID to Big Endian byte array 152 * 153 * @param uuid UUID to convert 154 * @return the byte array representing the UUID 155 */ 156 @NonNull uuidToBytes(@onNull UUID uuid)157 public static byte[] uuidToBytes(@NonNull UUID uuid) { 158 159 return ByteBuffer.allocate(UUID_LENGTH) 160 .order(ByteOrder.BIG_ENDIAN) 161 .putLong(uuid.getMostSignificantBits()) 162 .putLong(uuid.getLeastSignificantBits()) 163 .array(); 164 } 165 166 /** 167 * Convert Big Endian byte array to UUID 168 * 169 * @param bytes byte array to convert 170 * @return the UUID representing the byte array, or null if not a valid UUID 171 */ 172 @Nullable bytesToUUID(@onNull byte[] bytes)173 public static UUID bytesToUUID(@NonNull byte[] bytes) { 174 if (bytes.length != UUID_LENGTH) { 175 return null; 176 } 177 178 ByteBuffer buffer = ByteBuffer.wrap(bytes); 179 return new UUID(buffer.getLong(), buffer.getLong()); 180 } 181 182 /** 183 * Generate a random zero-filled string of given length 184 * 185 * @param length of string 186 * @return generated string 187 */ 188 @SuppressLint("DefaultLocale") // Should always have the same format regardless of locale generateRandomNumberString(int length)189 public static String generateRandomNumberString(int length) { 190 return String.format("%0" + length + "d", 191 ThreadLocalRandom.current().nextInt((int) Math.pow(10, length))); 192 } 193 194 /** 195 * Concatentate the given 2 byte arrays 196 * 197 * @param a input array 1 198 * @param b input array 2 199 * @return concatenated array of arrays 1 and 2 200 */ 201 @Nullable concatByteArrays(@ullable byte[] a, @Nullable byte[] b)202 public static byte[] concatByteArrays(@Nullable byte[] a, @Nullable byte[] b) { 203 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 204 try { 205 if (a != null) { 206 outputStream.write(a); 207 } 208 if (b != null) { 209 outputStream.write(b); 210 } 211 } catch (IOException e) { 212 return null; 213 } 214 return outputStream.toByteArray(); 215 } 216 217 /** 218 * Returns the content resolver for the given user. This can be used to put/get the 219 * user's settings. 220 * 221 * @param context The context of the package. 222 * @param userId The id of the user which the content resolver is being requested for. It also 223 * accepts {@link UserHandle#USER_CURRENT}. 224 */ getContentResolverForUser(Context context, @UserIdInt int userId)225 public static ContentResolver getContentResolverForUser(Context context, 226 @UserIdInt int userId) { 227 if (userId == UserHandle.CURRENT.getIdentifier()) { 228 userId = ActivityManager.getCurrentUser(); 229 } 230 return context 231 .createContextAsUser( 232 UserHandle.of(userId), /* flags= */ 0) 233 .getContentResolver(); 234 } 235 236 /** 237 * Checks if the type of the {@code event} matches {@code expectedType}. 238 * 239 * @param tag The tag for logging. 240 * @param event The event to check the type against {@code expectedType}. 241 * @param expectedType The expected event type. 242 * @return true if {@code event}'s type matches {@code expectedType}. 243 * Otherwise, log a wtf and return false. 244 */ isEventOfType(String tag, UserLifecycleEvent event, @UserLifecycleEventType int expectedType)245 public static boolean isEventOfType(String tag, UserLifecycleEvent event, 246 @UserLifecycleEventType int expectedType) { 247 if (event.getEventType() == expectedType) { 248 return true; 249 } 250 Slogf.wtf(tag, "Received an unexpected event: %s. Expected type: %s.", event, 251 lifecycleEventTypeToString(expectedType)); 252 return false; 253 } 254 255 /** 256 * Checks if the type of the {@code event} is one of the types in {@code expectedTypes}. 257 * 258 * @param tag The tag for logging. 259 * @param event The event to check the type against {@code expectedTypes}. 260 * @param expectedTypes The expected event types. Must not be empty. 261 * @return true if {@code event}'s type can be found in {@code expectedTypes}. 262 * Otherwise, log a wtf and return false. 263 */ isEventAnyOfTypes(String tag, UserLifecycleEvent event, @UserLifecycleEventType int... expectedTypes)264 public static boolean isEventAnyOfTypes(String tag, UserLifecycleEvent event, 265 @UserLifecycleEventType int... expectedTypes) { 266 for (int i = 0; i < expectedTypes.length; i++) { 267 if (event.getEventType() == expectedTypes[i]) { 268 return true; 269 } 270 } 271 StringJoiner expectedTyepsStringJoiner = new StringJoiner(","); 272 for (int index = 0; index < expectedTypes.length; index++) { 273 expectedTyepsStringJoiner.add(lifecycleEventTypeToString(expectedTypes[index])); 274 } 275 Slogf.wtf(tag, "Received an unexpected event: %s. Expected types: [%s]", event, 276 expectedTyepsStringJoiner.toString()); 277 return false; 278 } 279 280 /** 281 * Checks if the calling UID owns the give package. 282 * 283 * @throws SecurityException if the calling UID doesn't own the given package. 284 */ checkCalledByPackage(Context context, String packageName)285 public static void checkCalledByPackage(Context context, String packageName) { 286 int callingUid = Binder.getCallingUid(); 287 PackageManager pm = context.getPackageManager(); 288 int uidFromPm = INVALID_UID; 289 try { 290 uidFromPm = PackageManagerHelper.getPackageUidAsUser(pm, packageName, 291 UserManagerHelper.getUserId(callingUid)); 292 } catch (PackageManager.NameNotFoundException e) { 293 String msg = PACKAGE_NOT_FOUND + packageName; 294 throw new SecurityException(msg, e); 295 } 296 297 if (uidFromPm != callingUid) { 298 throw new SecurityException( 299 "Package " + packageName + " is not associated to UID " + callingUid); 300 } 301 } 302 303 /** 304 * Execute a runnable on the main thread 305 * 306 * @param action The code to run on the main thread. 307 */ runOnMain(Runnable action)308 public static void runOnMain(Runnable action) { 309 runOnLooper(Looper.getMainLooper(), action); 310 } 311 312 /** 313 * Execute a runnable in the given looper 314 * @param looper Looper to run the action. 315 * @param action The code to run. 316 */ runOnLooper(Looper looper, Runnable action)317 public static void runOnLooper(Looper looper, Runnable action) { 318 new Handler(looper).post(action); 319 } 320 321 /** 322 * Execute an empty runnable in the looper of the handler thread 323 * specified by the name. 324 * 325 * @param name Name of the handler thread in which to run the empty 326 * runnable. 327 */ runEmptyRunnableOnLooperSync(String name)328 public static void runEmptyRunnableOnLooperSync(String name) { 329 runOnLooperSync(getHandlerThread(name).getLooper(), () -> {}); 330 } 331 332 /** 333 * Execute a call on the application's main thread, blocking until it is 334 * complete. Useful for doing things that are not thread-safe, such as 335 * looking at or modifying the view hierarchy. 336 * 337 * @param action The code to run on the main thread. 338 */ runOnMainSync(Runnable action)339 public static void runOnMainSync(Runnable action) { 340 runOnLooperSync(Looper.getMainLooper(), action); 341 } 342 343 /** 344 * Execute a delayed call on the application's main thread, blocking until it is 345 * complete. See {@link #runOnMainSync(Runnable)} 346 * 347 * @param action The code to run on the main thread. 348 * @param delayMillis The delay (in milliseconds) until the Runnable will be executed. 349 */ runOnMainSyncDelayed(Runnable action, long delayMillis)350 public static void runOnMainSyncDelayed(Runnable action, long delayMillis) { 351 runOnLooperSyncDelayed(Looper.getMainLooper(), action, delayMillis); 352 } 353 354 /** 355 * Execute a call on the given Looper thread, blocking until it is 356 * complete. 357 * 358 * @param looper Looper to run the action. 359 * @param action The code to run on the looper thread. 360 */ runOnLooperSync(Looper looper, Runnable action)361 public static void runOnLooperSync(Looper looper, Runnable action) { 362 runOnLooperSyncDelayed(looper, action, /* delayMillis */ 0L); 363 } 364 365 /** 366 * Executes a delayed call on the given Looper thread, blocking until it is complete. 367 * 368 * @param looper Looper to run the action. 369 * @param action The code to run on the looper thread. 370 * @param delayMillis The delay (in milliseconds) until the Runnable will be executed. 371 */ runOnLooperSyncDelayed(Looper looper, Runnable action, long delayMillis)372 public static void runOnLooperSyncDelayed(Looper looper, Runnable action, long delayMillis) { 373 if (Looper.myLooper() == looper) { 374 // requested thread is the same as the current thread. call directly. 375 action.run(); 376 } else { 377 Handler handler = new Handler(looper); 378 SyncRunnable sr = new SyncRunnable(action); 379 handler.postDelayed(sr, delayMillis); 380 sr.waitForComplete(); 381 } 382 } 383 384 /** 385 * Executes a runnable on the common thread. Useful for doing any kind of asynchronous work 386 * across the car related code that doesn't need to be on the main thread. 387 * 388 * @param action The code to run on the common thread. 389 */ runOnCommon(Runnable action)390 public static void runOnCommon(Runnable action) { 391 runOnLooper(getCommonHandlerThread().getLooper(), action); 392 } 393 394 private static final class SyncRunnable implements Runnable { 395 private final Runnable mTarget; 396 private volatile boolean mComplete = false; 397 SyncRunnable(Runnable target)398 public SyncRunnable(Runnable target) { 399 mTarget = target; 400 } 401 402 @Override run()403 public void run() { 404 mTarget.run(); 405 synchronized (this) { 406 mComplete = true; 407 notifyAll(); 408 } 409 } 410 waitForComplete()411 public void waitForComplete() { 412 synchronized (this) { 413 while (!mComplete) { 414 try { 415 wait(); 416 } catch (InterruptedException e) { 417 } 418 } 419 } 420 } 421 } 422 toFloatArray(List<Float> list)423 public static float[] toFloatArray(List<Float> list) { 424 int size = list.size(); 425 float[] array = new float[size]; 426 for (int i = 0; i < size; ++i) { 427 array[i] = list.get(i); 428 } 429 return array; 430 } 431 toLongArray(List<Long> list)432 public static long[] toLongArray(List<Long> list) { 433 int size = list.size(); 434 long[] array = new long[size]; 435 for (int i = 0; i < size; ++i) { 436 array[i] = list.get(i); 437 } 438 return array; 439 } 440 toIntArray(List<Integer> list)441 public static int[] toIntArray(List<Integer> list) { 442 int size = list.size(); 443 int[] array = new int[size]; 444 for (int i = 0; i < size; ++i) { 445 array[i] = list.get(i); 446 } 447 return array; 448 } 449 450 /** 451 * Converts array to an array list 452 */ asList(int[] array)453 public static ArrayList<Integer> asList(int[] array) { 454 Preconditions.checkArgument(array != null, "Array to convert to list can not be null"); 455 int size = array.length; 456 ArrayList<Integer> results = new ArrayList<>(size); 457 for (int i = 0; i < size; i++) { 458 results.add(array[i]); 459 } 460 return results; 461 } 462 toByteArray(List<Byte> list)463 public static byte[] toByteArray(List<Byte> list) { 464 int size = list.size(); 465 byte[] array = new byte[size]; 466 for (int i = 0; i < size; ++i) { 467 array[i] = list.get(i); 468 } 469 return array; 470 } 471 472 /** 473 * Converts values array to array set 474 */ toIntArraySet(int[] values)475 public static ArraySet<Integer> toIntArraySet(int[] values) { 476 Preconditions.checkArgument(values != null, 477 "Values to convert to array set must not be null"); 478 ArraySet<Integer> set = new ArraySet<>(values.length); 479 for (int c = 0; c < values.length; c++) { 480 set.add(values[c]); 481 } 482 483 return set; 484 } 485 486 /** 487 * Converts int-value array set to values array 488 */ toIntArray(ArraySet<Integer> set)489 public static int[] toIntArray(ArraySet<Integer> set) { 490 Preconditions.checkArgument(set != null, 491 "Int array set to converted to array must not be null"); 492 int size = set.size(); 493 int[] array = new int[size]; 494 for (int i = 0; i < size; ++i) { 495 array[i] = set.valueAt(i); 496 } 497 return array; 498 } 499 500 /** 501 * Returns delta between elapsed time to uptime = {@link SystemClock#elapsedRealtime()} - 502 * {@link SystemClock#uptimeMillis()}. Note that this value will be always >= 0. 503 */ getUptimeToElapsedTimeDeltaInMillis()504 public static long getUptimeToElapsedTimeDeltaInMillis() { 505 int retry = 0; 506 int max_retry = 2; // try only up to twice 507 while (true) { 508 long elapsed1 = SystemClock.elapsedRealtime(); 509 long uptime = SystemClock.uptimeMillis(); 510 long elapsed2 = SystemClock.elapsedRealtime(); 511 if (elapsed1 == elapsed2) { // avoid possible 1 ms fluctuation. 512 return elapsed1 - uptime; 513 } 514 retry++; 515 if (retry >= max_retry) { 516 return elapsed1 - uptime; 517 } 518 } 519 } 520 521 /** 522 * Gets a static instance of {@code HandlerThread} for the given {@code name}. If the thread 523 * does not exist, create one and start it before returning. 524 */ getHandlerThread(String name)525 public static HandlerThread getHandlerThread(String name) { 526 synchronized (sHandlerThreads) { 527 HandlerThread thread = sHandlerThreads.get(name); 528 if (thread == null || !thread.isAlive()) { 529 Slogf.i(TAG, "Starting HandlerThread:" + name); 530 thread = new HandlerThread(name); 531 thread.start(); 532 sHandlerThreads.put(name, thread); 533 } 534 return thread; 535 } 536 } 537 538 /** 539 * Gets the static instance of the common {@code HandlerThread} meant to be used across 540 * CarService. 541 */ getCommonHandlerThread()542 public static HandlerThread getCommonHandlerThread() { 543 return getHandlerThread(COMMON_HANDLER_THREAD_NAME); 544 } 545 546 /** 547 * Quits all the {@code HandlerThread} created via 548 * {@link#getHandlerThread(String)}. This is useful only for testing. 549 */ 550 @VisibleForTesting quitHandlerThreads()551 public static void quitHandlerThreads() throws InterruptedException { 552 ArrayList<HandlerThread> threads; 553 synchronized (sHandlerThreads) { 554 threads = new ArrayList<>(sHandlerThreads.values()); 555 } 556 for (int i = 0; i < threads.size(); i++) { 557 var thread = threads.get(i); 558 if (!thread.isAlive()) { 559 continue; 560 } 561 if (thread.quitSafely()) { 562 thread.join(); 563 } 564 } 565 synchronized (sHandlerThreads) { 566 for (int i = 0; i < sHandlerThreads.size(); i++) { 567 if (sHandlerThreads.valueAt(i).isAlive()) { 568 throw new IllegalStateException( 569 "Thread: " + sHandlerThreads.keyAt(i) + " is still alive after " 570 + "finishing all the tasks in the handler threads, maybe one of the " 571 + " pending task is creating a new handler thread?"); 572 } 573 } 574 } 575 } 576 577 /** 578 * Assert if binder call is coming from system process like system server or if it is called 579 * from its own process even if it is not system. The latter can happen in test environment. 580 * Note that car service runs as system user but test like car service test will not. 581 */ assertCallingFromSystemProcessOrSelf()582 public static void assertCallingFromSystemProcessOrSelf() { 583 if (isCallingFromSystemProcessOrSelf()) { 584 throw new SecurityException("Only allowed from system or self"); 585 } 586 } 587 588 /** 589 * @return true if binder call is coming from system process like system server or if it is 590 * called from its own process even if it is not system. 591 */ isCallingFromSystemProcessOrSelf()592 public static boolean isCallingFromSystemProcessOrSelf() { 593 int uid = Binder.getCallingUid(); 594 int pid = Binder.getCallingPid(); 595 return uid != Process.SYSTEM_UID && pid != Process.myPid(); 596 } 597 598 599 /** Utility for checking permission */ assertVehicleHalMockPermission(Context context)600 public static void assertVehicleHalMockPermission(Context context) { 601 assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL); 602 } 603 604 /** Utility for checking permission */ assertNavigationManagerPermission(Context context)605 public static void assertNavigationManagerPermission(Context context) { 606 assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER); 607 } 608 609 /** Utility for checking permission */ assertClusterManagerPermission(Context context)610 public static void assertClusterManagerPermission(Context context) { 611 assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL); 612 } 613 614 /** Utility for checking permission */ assertPowerPermission(Context context)615 public static void assertPowerPermission(Context context) { 616 assertPermission(context, Car.PERMISSION_CAR_POWER); 617 } 618 619 /** Utility for checking permission */ assertProjectionPermission(Context context)620 public static void assertProjectionPermission(Context context) { 621 assertPermission(context, Car.PERMISSION_CAR_PROJECTION); 622 } 623 624 /** Verify the calling context has the {@link Car#PERMISSION_CAR_PROJECTION_STATUS} */ assertProjectionStatusPermission(Context context)625 public static void assertProjectionStatusPermission(Context context) { 626 assertPermission(context, Car.PERMISSION_CAR_PROJECTION_STATUS); 627 } 628 629 /** Utility for checking permission */ assertAnyDiagnosticPermission(Context context)630 public static void assertAnyDiagnosticPermission(Context context) { 631 assertAnyPermission(context, 632 Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL, 633 Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR); 634 } 635 636 /** Utility for checking permission */ assertDrivingStatePermission(Context context)637 public static void assertDrivingStatePermission(Context context) { 638 assertPermission(context, Car.PERMISSION_CAR_DRIVING_STATE); 639 } 640 641 /** 642 * Verify the calling context has either {@link Car#PERMISSION_VMS_SUBSCRIBER} or 643 * {@link Car#PERMISSION_VMS_PUBLISHER} 644 */ assertAnyVmsPermission(Context context)645 public static void assertAnyVmsPermission(Context context) { 646 assertAnyPermission(context, 647 Car.PERMISSION_VMS_SUBSCRIBER, 648 Car.PERMISSION_VMS_PUBLISHER); 649 } 650 651 /** Utility for checking permission */ assertVmsPublisherPermission(Context context)652 public static void assertVmsPublisherPermission(Context context) { 653 assertPermission(context, Car.PERMISSION_VMS_PUBLISHER); 654 } 655 656 /** Utility for checking permission */ assertVmsSubscriberPermission(Context context)657 public static void assertVmsSubscriberPermission(Context context) { 658 assertPermission(context, Car.PERMISSION_VMS_SUBSCRIBER); 659 } 660 661 /** Utility for checking permission */ assertPermission(Context context, String permission)662 public static void assertPermission(Context context, String permission) { 663 if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { 664 throw new SecurityException("requires " + permission); 665 } 666 } 667 668 /** 669 * Checks to see if the caller has a permission. 670 * 671 * @return boolean TRUE if caller has the permission. 672 */ hasPermission(Context context, String permission)673 public static boolean hasPermission(Context context, String permission) { 674 return context.checkCallingOrSelfPermission(permission) 675 == PackageManager.PERMISSION_GRANTED; 676 } 677 678 /** Utility for checking permission */ assertAnyPermission(Context context, String... permissions)679 public static void assertAnyPermission(Context context, String... permissions) { 680 for (String permission : permissions) { 681 if (context.checkCallingOrSelfPermission(permission) 682 == PackageManager.PERMISSION_GRANTED) { 683 return; 684 } 685 } 686 throw new SecurityException("requires any of " + Arrays.toString(permissions)); 687 } 688 689 /** 690 * Turns a {@code SubscribeOptions} to {@code 691 * android.hardware.automotive.vehicle.V2_0.SubscribeOptions} 692 */ subscribeOptionsToHidl( SubscribeOptions options)693 public static android.hardware.automotive.vehicle.V2_0.SubscribeOptions subscribeOptionsToHidl( 694 SubscribeOptions options) { 695 android.hardware.automotive.vehicle.V2_0.SubscribeOptions hidlOptions = 696 new android.hardware.automotive.vehicle.V2_0.SubscribeOptions(); 697 hidlOptions.propId = options.propId; 698 hidlOptions.sampleRate = options.sampleRate; 699 // HIDL backend requires flags to be set although it is not used any more. 700 hidlOptions.flags = android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR; 701 // HIDL backend does not support area IDs, so we ignore options.areaId field. 702 return hidlOptions; 703 } 704 705 /** 706 * Returns {@code true} if the current configuration supports multiple users on multiple 707 * displays. 708 */ isMultipleUsersOnMultipleDisplaysSupported(UserManager userManager)709 public static boolean isMultipleUsersOnMultipleDisplaysSupported(UserManager userManager) { 710 return UserManagerHelper.isVisibleBackgroundUsersSupported(userManager); 711 } 712 713 /** 714 * Returns {@code true} if the current configuration supports visible background users on 715 * default display. 716 */ isVisibleBackgroundUsersOnDefaultDisplaySupported( UserManager userManager)717 public static boolean isVisibleBackgroundUsersOnDefaultDisplaySupported( 718 UserManager userManager) { 719 return UserManagerHelper.isVisibleBackgroundUsersOnDefaultDisplaySupported(userManager); 720 } 721 722 /** 723 * Starts Activity for the given {@code userId} and {@code displayId}. 724 * 725 * @return {@code true} when starting activity succeeds. It can fail in situation like secondary 726 * home package not existing. 727 */ startHomeForUserAndDisplay(Context context, @UserIdInt int userId, int displayId)728 public static boolean startHomeForUserAndDisplay(Context context, 729 @UserIdInt int userId, int displayId) { 730 if (DBG) { 731 Slogf.d(TAG, "Starting HOME for user: %d, display:%d", userId, displayId); 732 } 733 Intent homeIntent = new Intent(Intent.ACTION_MAIN) 734 .addCategory(Intent.CATEGORY_HOME); 735 ActivityOptions activityOptions = ActivityOptions.makeBasic() 736 .setLaunchDisplayId(displayId); 737 try { 738 ContextHelper.startActivityAsUser(context, homeIntent, activityOptions.toBundle(), 739 UserHandle.of(userId)); 740 if (DBG) { 741 Slogf.d(TAG, "Started HOME for user: %d, display:%d", userId, displayId); 742 } 743 return true; 744 } catch (Exception e) { 745 Slogf.w(TAG, e, "Cannot start HOME for user: %d, display:%d", userId, displayId); 746 return false; 747 } 748 } 749 750 /** 751 * Starts SystemUI component for a particular user - should be called for non-current user only. 752 * 753 * @return {@code true} when starting service succeeds. It can fail in situation like the 754 * SystemUI service component not being defined. 755 */ startSystemUiForUser(Context context, @UserIdInt int userId)756 public static boolean startSystemUiForUser(Context context, @UserIdInt int userId) { 757 if (DBG) Slogf.d(TAG, "Start SystemUI for user: %d", userId); 758 Preconditions.checkArgument(userId != UserHandle.SYSTEM.getIdentifier(), 759 "Cannot start SystemUI for the system user"); 760 Preconditions.checkArgument(userId != ActivityManager.getCurrentUser(), 761 "Cannot start SystemUI for the current foreground user"); 762 763 // TODO (b/261192740): add EventLog for SystemUI starting 764 ComponentName sysuiComponent = PackageManagerHelper.getSystemUiServiceComponent(context); 765 Intent sysUIIntent = new Intent().setComponent(sysuiComponent); 766 try { 767 context.bindServiceAsUser(sysUIIntent, sEmptyServiceConnection, 768 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.of(userId)); 769 return true; 770 } catch (Exception e) { 771 Slogf.w(TAG, e, "Cannot start SysUI component %s for user %d", sysuiComponent, 772 userId); 773 return false; 774 } 775 } 776 777 // The callbacks are not called actually, because SystemUI returns null for IBinder. 778 private static final ServiceConnection sEmptyServiceConnection = new ServiceConnection() { 779 @Override 780 public void onServiceConnected(ComponentName name, IBinder service) {} 781 782 @Override 783 public void onServiceDisconnected(ComponentName name) {} 784 }; 785 786 /** 787 * Stops the SystemUI component for a particular user - this function should not be called 788 * for the system user. 789 */ stopSystemUiForUser(Context context, @UserIdInt int userId)790 public static void stopSystemUiForUser(Context context, @UserIdInt int userId) { 791 Preconditions.checkArgument(userId != UserHandle.SYSTEM.getIdentifier(), 792 "Cannot stop SystemUI for the system user"); 793 // TODO (b/261192740): add EventLog for SystemUI stopping 794 String sysUiPackage = PackageManagerHelper.getSystemUiPackageName(context); 795 PackageManagerHelper.forceStopPackageAsUserEvenWhenStopping(context, sysUiPackage, userId); 796 } 797 798 /** 799 * Starts UserPickerActivity for the given {@code userId} and {@code displayId}. 800 * 801 * @return {@code true} when starting activity succeeds. It can fail in situation like 802 * package not existing. 803 */ startUserPickerOnDisplay(Context context, int displayId, String userPickerActivityPackage)804 public static boolean startUserPickerOnDisplay(Context context, 805 int displayId, String userPickerActivityPackage) { 806 if (DBG) { 807 Slogf.d(TAG, "Starting user picker on display:%d", displayId); 808 } 809 // FLAG_ACTIVITY_MULTIPLE_TASK ensures the user picker can show up on multiple displays. 810 Intent intent = new Intent() 811 .setComponent(ComponentName.unflattenFromString( 812 userPickerActivityPackage)) 813 .addFlags(FLAG_ACTIVITY_NEW_TASK) 814 .setData(Uri.parse("data://com.android.car/userpicker/display" + displayId)); 815 ActivityOptions activityOptions = ActivityOptions.makeBasic() 816 .setLaunchDisplayId(displayId); 817 try { 818 // Start the user picker as user 0. 819 ContextHelper.startActivityAsUser(context, intent, activityOptions.toBundle(), 820 UserHandle.SYSTEM); 821 return true; 822 } catch (Exception e) { 823 Slogf.w(TAG, e, "Cannot start user picker as user 0 on display:%d", displayId); 824 return false; 825 } 826 } 827 828 /** 829 * Generates a random string which consists of captial letters and numbers. 830 */ 831 @SuppressLint("DefaultLocale") // Should always have the same format regardless of locale generateRandomAlphaNumericString(int length)832 public static String generateRandomAlphaNumericString(int length) { 833 StringBuilder sb = new StringBuilder(); 834 835 int poolSize = CHAR_POOL_FOR_RANDOM_STRING.length; 836 for (int i = 0; i < length; i++) { 837 sb.append(CHAR_POOL_FOR_RANDOM_STRING[ThreadLocalRandom.current().nextInt(poolSize)]); 838 } 839 return sb.toString(); 840 } 841 842 /** 843 * Encrypts byte array with the keys stored in {@code keyAlias} using AES. 844 * 845 * @return Encrypted data and initialization vector in {@link EncryptedData}. {@code null} in 846 * case of errors. 847 */ 848 @Nullable encryptData(byte[] data, String keyAlias)849 public static EncryptedData encryptData(byte[] data, String keyAlias) { 850 SecretKey secretKey = getOrCreateSecretKey(keyAlias); 851 if (secretKey == null) { 852 Slogf.e(TAG, "Failed to encrypt data: cannot get a secret key (keyAlias: %s)", 853 keyAlias); 854 return null; 855 } 856 try { 857 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 858 cipher.init(Cipher.ENCRYPT_MODE, secretKey); 859 return new EncryptedData(cipher.doFinal(data), cipher.getIV()); 860 } catch (Exception e) { 861 Slogf.e(TAG, e, "Failed to encrypt data: keyAlias=%s", keyAlias); 862 return null; 863 } 864 } 865 866 /** 867 * Decrypts byte array with the keys stored in {@code keyAlias} using AES. 868 * 869 * @return Decrypted data in byte array. {@code null} in case of errors. 870 */ 871 @Nullable decryptData(EncryptedData data, String keyAlias)872 public static byte[] decryptData(EncryptedData data, String keyAlias) { 873 SecretKey secretKey = getOrCreateSecretKey(keyAlias); 874 if (secretKey == null) { 875 Slogf.e(TAG, "Failed to decrypt data: cannot get a secret key (keyAlias: %s)", 876 keyAlias); 877 return null; 878 } 879 try { 880 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 881 GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, data.getIv()); 882 cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); 883 return cipher.doFinal(data.getEncryptedData()); 884 } catch (Exception e) { 885 Slogf.e(TAG, e, "Failed to decrypt data: keyAlias=%s", keyAlias); 886 return null; 887 } 888 } 889 890 /** 891 * Class to hold encrypted data and its initialization vector. 892 */ 893 public static final class EncryptedData { 894 private final byte[] mEncryptedData; 895 private final byte[] mIv; 896 EncryptedData(byte[] encryptedData, byte[] iv)897 public EncryptedData(byte[] encryptedData, byte[] iv) { 898 mEncryptedData = encryptedData; 899 mIv = iv; 900 } 901 getEncryptedData()902 public byte[] getEncryptedData() { 903 return mEncryptedData; 904 } 905 getIv()906 public byte[] getIv() { 907 return mIv; 908 } 909 910 @Override equals(Object other)911 public boolean equals(Object other) { 912 if (this == other) return true; 913 if (!(other instanceof EncryptedData)) return false; 914 EncryptedData data = (EncryptedData) other; 915 return Arrays.equals(mEncryptedData, data.mEncryptedData) 916 && Arrays.equals(mIv, data.mIv); 917 } 918 919 @Override hashCode()920 public int hashCode() { 921 return Objects.hash(Arrays.hashCode(mEncryptedData), Arrays.hashCode(mIv)); 922 } 923 } 924 925 @Nullable getOrCreateSecretKey(String keyAlias)926 private static SecretKey getOrCreateSecretKey(String keyAlias) { 927 try { 928 KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE_NAME); 929 keyStore.load(/* KeyStore.LoadStoreParameter= */ null); 930 if (keyStore.containsAlias(keyAlias)) { 931 SecretKeyEntry secretKeyEntry = (SecretKeyEntry) keyStore.getEntry(keyAlias, 932 /* protParam= */ null); 933 if (secretKeyEntry != null) { 934 return secretKeyEntry.getSecretKey(); 935 } 936 Slogf.e(TAG, "Android key store contains the alias (%s) but the secret key " 937 + "entry is null", keyAlias); 938 return null; 939 } 940 KeyGenerator keyGenerator = KeyGenerator.getInstance( 941 KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE_NAME); 942 KeyGenParameterSpec keyGenParameterSpec = 943 new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT 944 | KeyProperties.PURPOSE_DECRYPT) 945 .setBlockModes(KeyProperties.BLOCK_MODE_GCM) 946 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) 947 .build(); 948 keyGenerator.init(keyGenParameterSpec); 949 return keyGenerator.generateKey(); 950 } catch (Exception e) { 951 Slogf.e(TAG, "Failed to get or create a secret key for the alias (%s)", keyAlias); 952 return null; 953 } 954 } 955 } 956