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