• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import static com.android.car.internal.util.VersionUtils.isPlatformVersionAtLeastU;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.SuppressLint;
29 import android.annotation.UserIdInt;
30 import android.app.ActivityManager;
31 import android.app.ActivityOptions;
32 import android.car.Car;
33 import android.car.builtin.content.ContextHelper;
34 import android.car.builtin.content.pm.PackageManagerHelper;
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.UUID;
77 import java.util.concurrent.ThreadLocalRandom;
78 import java.util.stream.Collectors;
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     /** Empty int array */
94     public  static final int[] EMPTY_INT_ARRAY = new int[0];
95     private static final String COMMON_HANDLER_THREAD_NAME =
96             "CarServiceUtils_COMMON_HANDLER_THREAD";
97     private static final byte[] CHAR_POOL_FOR_RANDOM_STRING =
98             "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes();
99 
100     private static final String PACKAGE_NOT_FOUND = "Package not found:";
101     private static final String ANDROID_KEYSTORE_NAME = "AndroidKeyStore";
102     private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
103     private static final int GCM_TAG_LENGTH = 128;
104 
105     /** K: class name, V: HandlerThread */
106     private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>();
107 
108     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
109             details = "private constructor")
CarServiceUtils()110     private CarServiceUtils() {
111         throw new UnsupportedOperationException("contains only static methods");
112     }
113 
114     /**
115      * Returns a byte buffer corresponding to the passed long argument.
116      *
117      * @param primitive data to convert format.
118      */
longToBytes(long primitive)119     public static byte[] longToBytes(long primitive) {
120         ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
121         buffer.putLong(primitive);
122         return buffer.array();
123     }
124 
125     /**
126      * Returns a byte buffer corresponding to the passed long argument.
127      *
128      * @param array data to convert format.
129      */
bytesToLong(byte[] array)130     public static long bytesToLong(byte[] array) {
131         ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
132         buffer.put(array);
133         buffer.flip();
134         long value = buffer.getLong();
135         return value;
136     }
137 
138     /**
139      * Returns a String in Hex format that is formed from the bytes in the byte array
140      * Useful for debugging
141      *
142      * @param array the byte array
143      * @return the Hex string version of the input byte array
144      */
byteArrayToHexString(byte[] array)145     public static String byteArrayToHexString(byte[] array) {
146         StringBuilder sb = new StringBuilder(array.length * 2);
147         for (byte b : array) {
148             sb.append(String.format("%02x", b));
149         }
150         return sb.toString();
151     }
152 
153     /**
154      * Convert UUID to Big Endian byte array
155      *
156      * @param uuid UUID to convert
157      * @return the byte array representing the UUID
158      */
159     @NonNull
uuidToBytes(@onNull UUID uuid)160     public static byte[] uuidToBytes(@NonNull UUID uuid) {
161 
162         return ByteBuffer.allocate(UUID_LENGTH)
163                 .order(ByteOrder.BIG_ENDIAN)
164                 .putLong(uuid.getMostSignificantBits())
165                 .putLong(uuid.getLeastSignificantBits())
166                 .array();
167     }
168 
169     /**
170      * Convert Big Endian byte array to UUID
171      *
172      * @param bytes byte array to convert
173      * @return the UUID representing the byte array, or null if not a valid UUID
174      */
175     @Nullable
bytesToUUID(@onNull byte[] bytes)176     public static UUID bytesToUUID(@NonNull byte[] bytes) {
177         if (bytes.length != UUID_LENGTH) {
178             return null;
179         }
180 
181         ByteBuffer buffer = ByteBuffer.wrap(bytes);
182         return new UUID(buffer.getLong(), buffer.getLong());
183     }
184 
185     /**
186      * Generate a random zero-filled string of given length
187      *
188      * @param length of string
189      * @return generated string
190      */
191     @SuppressLint("DefaultLocale")  // Should always have the same format regardless of locale
generateRandomNumberString(int length)192     public static String generateRandomNumberString(int length) {
193         return String.format("%0" + length + "d",
194                 ThreadLocalRandom.current().nextInt((int) Math.pow(10, length)));
195     }
196 
197     /**
198      * Concatentate the given 2 byte arrays
199      *
200      * @param a input array 1
201      * @param b input array 2
202      * @return concatenated array of arrays 1 and 2
203      */
204     @Nullable
concatByteArrays(@ullable byte[] a, @Nullable byte[] b)205     public static byte[] concatByteArrays(@Nullable byte[] a, @Nullable byte[] b) {
206         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
207         try {
208             if (a != null) {
209                 outputStream.write(a);
210             }
211             if (b != null) {
212                 outputStream.write(b);
213             }
214         } catch (IOException e) {
215             return null;
216         }
217         return outputStream.toByteArray();
218     }
219 
220     /**
221      * Returns the content resolver for the given user. This can be used to put/get the
222      * user's settings.
223      *
224      * @param context The context of the package.
225      * @param userId The id of the user which the content resolver is being requested for. It also
226      * accepts {@link UserHandle#USER_CURRENT}.
227      */
getContentResolverForUser(Context context, @UserIdInt int userId)228     public static ContentResolver getContentResolverForUser(Context context,
229             @UserIdInt int userId) {
230         if (userId == UserHandle.CURRENT.getIdentifier()) {
231             userId = ActivityManager.getCurrentUser();
232         }
233         return context
234                 .createContextAsUser(
235                         UserHandle.of(userId), /* flags= */ 0)
236                 .getContentResolver();
237     }
238 
239     /**
240      * Checks if the type of the {@code event} matches {@code expectedType}.
241      *
242      * @param tag The tag for logging.
243      * @param event The event to check the type against {@code expectedType}.
244      * @param expectedType The expected event type.
245      * @return true if {@code event}'s type matches {@code expectedType}.
246      *         Otherwise, log a wtf and return false.
247      */
isEventOfType(String tag, UserLifecycleEvent event, @UserLifecycleEventType int expectedType)248     public static boolean isEventOfType(String tag, UserLifecycleEvent event,
249             @UserLifecycleEventType int expectedType) {
250         if (event.getEventType() == expectedType) {
251             return true;
252         }
253         Slogf.wtf(tag, "Received an unexpected event: %s. Expected type: %s.", event,
254                 lifecycleEventTypeToString(expectedType));
255         return false;
256     }
257 
258     /**
259      * Checks if the type of the {@code event} is one of the types in {@code expectedTypes}.
260      *
261      * @param tag The tag for logging.
262      * @param event The event to check the type against {@code expectedTypes}.
263      * @param expectedTypes The expected event types. Must not be empty.
264      * @return true if {@code event}'s type can be found in {@code expectedTypes}.
265      *         Otherwise, log a wtf and return false.
266      */
isEventAnyOfTypes(String tag, UserLifecycleEvent event, @UserLifecycleEventType int... expectedTypes)267     public static boolean isEventAnyOfTypes(String tag, UserLifecycleEvent event,
268             @UserLifecycleEventType int... expectedTypes) {
269         for (int i = 0; i < expectedTypes.length; i++) {
270             if (event.getEventType() == expectedTypes[i]) {
271                 return true;
272             }
273         }
274         Slogf.wtf(tag, "Received an unexpected event: %s. Expected types: [%s]", event,
275                 Arrays.stream(expectedTypes).mapToObj(t -> lifecycleEventTypeToString(t)).collect(
276                         Collectors.joining(",")));
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      * Returns delta between elapsed time to uptime = {@link SystemClock#elapsedRealtime()} -
488      * {@link SystemClock#uptimeMillis()}. Note that this value will be always >= 0.
489      */
getUptimeToElapsedTimeDeltaInMillis()490     public static long getUptimeToElapsedTimeDeltaInMillis() {
491         int retry = 0;
492         int max_retry = 2; // try only up to twice
493         while (true) {
494             long elapsed1 = SystemClock.elapsedRealtime();
495             long uptime = SystemClock.uptimeMillis();
496             long elapsed2 = SystemClock.elapsedRealtime();
497             if (elapsed1 == elapsed2) { // avoid possible 1 ms fluctuation.
498                 return elapsed1 - uptime;
499             }
500             retry++;
501             if (retry >= max_retry) {
502                 return elapsed1 - uptime;
503             }
504         }
505     }
506 
507     /**
508      * Gets a static instance of {@code HandlerThread} for the given {@code name}. If the thread
509      * does not exist, create one and start it before returning.
510      */
getHandlerThread(String name)511     public static HandlerThread getHandlerThread(String name) {
512         synchronized (sHandlerThreads) {
513             HandlerThread thread = sHandlerThreads.get(name);
514             if (thread == null || !thread.isAlive()) {
515                 Slogf.i(TAG, "Starting HandlerThread:" + name);
516                 thread = new HandlerThread(name);
517                 thread.start();
518                 sHandlerThreads.put(name, thread);
519             }
520             return thread;
521         }
522     }
523 
524     /**
525      * Gets the static instance of the common {@code HandlerThread} meant to be used across
526      * CarService.
527      */
getCommonHandlerThread()528     public static HandlerThread getCommonHandlerThread() {
529         return getHandlerThread(COMMON_HANDLER_THREAD_NAME);
530     }
531 
532     /**
533      * Finishes all queued {@code Handler} tasks for {@code HandlerThread} created via
534      * {@link#getHandlerThread(String)}. This is useful only for testing.
535      */
536     @VisibleForTesting
finishAllHandlerTasks()537     public static void finishAllHandlerTasks() {
538         ArrayList<HandlerThread> threads;
539         synchronized (sHandlerThreads) {
540             threads = new ArrayList<>(sHandlerThreads.values());
541         }
542         ArrayList<SyncRunnable> syncs = new ArrayList<>(threads.size());
543         for (int i = 0; i < threads.size(); i++) {
544             if (!threads.get(i).isAlive()) {
545                 continue;
546             }
547             Handler handler = new Handler(threads.get(i).getLooper());
548             SyncRunnable sr = new SyncRunnable(() -> { });
549             if (handler.post(sr)) {
550                 // Track the threads only where SyncRunnable is posted successfully.
551                 syncs.add(sr);
552             }
553         }
554         for (int i = 0; i < syncs.size(); i++) {
555             syncs.get(i).waitForComplete();
556         }
557     }
558 
559     /**
560      * Assert if binder call is coming from system process like system server or if it is called
561      * from its own process even if it is not system. The latter can happen in test environment.
562      * Note that car service runs as system user but test like car service test will not.
563      */
assertCallingFromSystemProcessOrSelf()564     public static void assertCallingFromSystemProcessOrSelf() {
565         if (isCallingFromSystemProcessOrSelf()) {
566             throw new SecurityException("Only allowed from system or self");
567         }
568     }
569 
570     /**
571      * @return true if binder call is coming from system process like system server or if it is
572      * called from its own process even if it is not system.
573      */
isCallingFromSystemProcessOrSelf()574     public static boolean isCallingFromSystemProcessOrSelf() {
575         int uid = Binder.getCallingUid();
576         int pid = Binder.getCallingPid();
577         return uid != Process.SYSTEM_UID && pid != Process.myPid();
578     }
579 
580 
581     /** Utility for checking permission */
assertVehicleHalMockPermission(Context context)582     public static void assertVehicleHalMockPermission(Context context) {
583         assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
584     }
585 
586     /** Utility for checking permission */
assertNavigationManagerPermission(Context context)587     public static void assertNavigationManagerPermission(Context context) {
588         assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
589     }
590 
591     /** Utility for checking permission */
assertClusterManagerPermission(Context context)592     public static void assertClusterManagerPermission(Context context) {
593         assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
594     }
595 
596     /** Utility for checking permission */
assertPowerPermission(Context context)597     public static void assertPowerPermission(Context context) {
598         assertPermission(context, Car.PERMISSION_CAR_POWER);
599     }
600 
601     /** Utility for checking permission */
assertProjectionPermission(Context context)602     public static void assertProjectionPermission(Context context) {
603         assertPermission(context, Car.PERMISSION_CAR_PROJECTION);
604     }
605 
606     /** Verify the calling context has the {@link Car#PERMISSION_CAR_PROJECTION_STATUS} */
assertProjectionStatusPermission(Context context)607     public static void assertProjectionStatusPermission(Context context) {
608         assertPermission(context, Car.PERMISSION_CAR_PROJECTION_STATUS);
609     }
610 
611     /** Utility for checking permission */
assertAnyDiagnosticPermission(Context context)612     public static void assertAnyDiagnosticPermission(Context context) {
613         assertAnyPermission(context,
614                 Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL,
615                 Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR);
616     }
617 
618     /** Utility for checking permission */
assertDrivingStatePermission(Context context)619     public static void assertDrivingStatePermission(Context context) {
620         assertPermission(context, Car.PERMISSION_CAR_DRIVING_STATE);
621     }
622 
623     /**
624      * Verify the calling context has either {@link Car#PERMISSION_VMS_SUBSCRIBER} or
625      * {@link Car#PERMISSION_VMS_PUBLISHER}
626      */
assertAnyVmsPermission(Context context)627     public static void assertAnyVmsPermission(Context context) {
628         assertAnyPermission(context,
629                 Car.PERMISSION_VMS_SUBSCRIBER,
630                 Car.PERMISSION_VMS_PUBLISHER);
631     }
632 
633     /** Utility for checking permission */
assertVmsPublisherPermission(Context context)634     public static void assertVmsPublisherPermission(Context context) {
635         assertPermission(context, Car.PERMISSION_VMS_PUBLISHER);
636     }
637 
638     /** Utility for checking permission */
assertVmsSubscriberPermission(Context context)639     public static void assertVmsSubscriberPermission(Context context) {
640         assertPermission(context, Car.PERMISSION_VMS_SUBSCRIBER);
641     }
642 
643     /** Utility for checking permission */
assertPermission(Context context, String permission)644     public static void assertPermission(Context context, String permission) {
645         if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
646             throw new SecurityException("requires " + permission);
647         }
648     }
649 
650     /**
651      * Checks to see if the caller has a permission.
652      *
653      * @return boolean TRUE if caller has the permission.
654      */
hasPermission(Context context, String permission)655     public static boolean hasPermission(Context context, String permission) {
656         return context.checkCallingOrSelfPermission(permission)
657                 == PackageManager.PERMISSION_GRANTED;
658     }
659 
660     /** Utility for checking permission */
assertAnyPermission(Context context, String... permissions)661     public static void assertAnyPermission(Context context, String... permissions) {
662         for (String permission : permissions) {
663             if (context.checkCallingOrSelfPermission(permission)
664                     == PackageManager.PERMISSION_GRANTED) {
665                 return;
666             }
667         }
668         throw new SecurityException("requires any of " + Arrays.toString(permissions));
669     }
670 
671     /**
672      * Turns a {@code SubscribeOptions} to {@code
673      * android.hardware.automotive.vehicle.V2_0.SubscribeOptions}
674      */
subscribeOptionsToHidl( SubscribeOptions options)675     public static android.hardware.automotive.vehicle.V2_0.SubscribeOptions subscribeOptionsToHidl(
676             SubscribeOptions options) {
677         android.hardware.automotive.vehicle.V2_0.SubscribeOptions hidlOptions =
678                 new android.hardware.automotive.vehicle.V2_0.SubscribeOptions();
679         hidlOptions.propId = options.propId;
680         hidlOptions.sampleRate = options.sampleRate;
681         // HIDL backend requires flags to be set although it is not used any more.
682         hidlOptions.flags = android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR;
683         // HIDL backend does not support area IDs, so we ignore options.areaId field.
684         return hidlOptions;
685     }
686 
687     /**
688      * Returns {@code true} if the current configuration supports multiple users on multiple
689      * displays.
690      */
isMultipleUsersOnMultipleDisplaysSupported(UserManager userManager)691     public static boolean isMultipleUsersOnMultipleDisplaysSupported(UserManager userManager) {
692         return isPlatformVersionAtLeastU()
693                 && UserManagerHelper.isVisibleBackgroundUsersSupported(userManager);
694     }
695 
696     /**
697      * Returns {@code true} if the current configuration supports visible background users on
698      * default display.
699      */
isVisibleBackgroundUsersOnDefaultDisplaySupported( UserManager userManager)700     public static boolean isVisibleBackgroundUsersOnDefaultDisplaySupported(
701             UserManager userManager) {
702         return isPlatformVersionAtLeastU()
703                 && UserManagerHelper.isVisibleBackgroundUsersOnDefaultDisplaySupported(userManager);
704     }
705 
706     /**
707      * Starts Activity for the given {@code userId} and {@code displayId}.
708      *
709      * @return {@code true} when starting activity succeeds. It can fail in situation like secondary
710      *         home package not existing.
711      */
startHomeForUserAndDisplay(Context context, @UserIdInt int userId, int displayId)712     public static boolean startHomeForUserAndDisplay(Context context,
713             @UserIdInt int userId, int displayId) {
714         if (DBG) {
715             Slogf.d(TAG, "Starting HOME for user: %d, display:%d", userId, displayId);
716         }
717         Intent homeIntent = new Intent(Intent.ACTION_MAIN)
718                 .addCategory(Intent.CATEGORY_HOME);
719         ActivityOptions activityOptions = ActivityOptions.makeBasic()
720                 .setLaunchDisplayId(displayId);
721         try {
722             ContextHelper.startActivityAsUser(context, homeIntent, activityOptions.toBundle(),
723                     UserHandle.of(userId));
724             if (DBG) {
725                 Slogf.d(TAG, "Started HOME for user: %d, display:%d", userId, displayId);
726             }
727             return true;
728         } catch (Exception e) {
729             Slogf.w(TAG, e, "Cannot start HOME for user: %d, display:%d", userId, displayId);
730             return false;
731         }
732     }
733 
734     /**
735      * Starts SystemUI component for a particular user - should be called for non-current user only.
736      *
737      * @return {@code true} when starting service succeeds. It can fail in situation like the
738      * SystemUI service component not being defined.
739      */
startSystemUiForUser(Context context, @UserIdInt int userId)740     public static boolean startSystemUiForUser(Context context, @UserIdInt int userId) {
741         if (!isPlatformVersionAtLeastU()) {
742             return false;
743         }
744         if (DBG) Slogf.d(TAG, "Start SystemUI for user: %d", userId);
745         Preconditions.checkArgument(userId != UserHandle.SYSTEM.getIdentifier(),
746                 "Cannot start SystemUI for the system user");
747         Preconditions.checkArgument(userId != ActivityManager.getCurrentUser(),
748                 "Cannot start SystemUI for the current foreground user");
749 
750         // TODO (b/261192740): add EventLog for SystemUI starting
751         ComponentName sysuiComponent = PackageManagerHelper.getSystemUiServiceComponent(context);
752         Intent sysUIIntent = new Intent().setComponent(sysuiComponent);
753         try {
754             context.bindServiceAsUser(sysUIIntent, sEmptyServiceConnection,
755                     Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.of(userId));
756             return true;
757         } catch (Exception e) {
758             Slogf.w(TAG, e, "Cannot start SysUI component %s for user %d", sysuiComponent,
759                     userId);
760             return false;
761         }
762     }
763 
764     // The callbacks are not called actually, because SystemUI returns null for IBinder.
765     private static final ServiceConnection sEmptyServiceConnection = new ServiceConnection() {
766         @Override
767         public void onServiceConnected(ComponentName name, IBinder service) {}
768 
769         @Override
770         public void onServiceDisconnected(ComponentName name) {}
771     };
772 
773     /**
774      * Stops the SystemUI component for a particular user - this function should not be called
775      * for the system user.
776      */
stopSystemUiForUser(Context context, @UserIdInt int userId)777     public static void stopSystemUiForUser(Context context, @UserIdInt int userId) {
778         if (!isPlatformVersionAtLeastU()) {
779             return;
780         }
781         Preconditions.checkArgument(userId != UserHandle.SYSTEM.getIdentifier(),
782                 "Cannot stop SystemUI for the system user");
783         // TODO (b/261192740): add EventLog for SystemUI stopping
784         String sysUiPackage = PackageManagerHelper.getSystemUiPackageName(context);
785         PackageManagerHelper.forceStopPackageAsUserEvenWhenStopping(context, sysUiPackage, userId);
786     }
787 
788     /**
789      * Starts UserPickerActivity for the given {@code userId} and {@code displayId}.
790      *
791      * @return {@code true} when starting activity succeeds. It can fail in situation like
792      * package not existing.
793      */
startUserPickerOnDisplay(Context context, int displayId, String userPickerActivityPackage)794     public static boolean startUserPickerOnDisplay(Context context,
795             int displayId, String userPickerActivityPackage) {
796         if (DBG) {
797             Slogf.d(TAG, "Starting user picker on display:%d", displayId);
798         }
799         // FLAG_ACTIVITY_MULTIPLE_TASK ensures the user picker can show up on multiple displays.
800         Intent intent = new Intent()
801                 .setComponent(ComponentName.unflattenFromString(
802                     userPickerActivityPackage))
803                 .addFlags(FLAG_ACTIVITY_NEW_TASK)
804                 .setData(Uri.parse("data://com.android.car/userpicker/display" + displayId));
805         ActivityOptions activityOptions = ActivityOptions.makeBasic()
806                 .setLaunchDisplayId(displayId);
807         try {
808             // Start the user picker as user 0.
809             ContextHelper.startActivityAsUser(context, intent, activityOptions.toBundle(),
810                     UserHandle.SYSTEM);
811             return true;
812         } catch (Exception e) {
813             Slogf.w(TAG, e, "Cannot start user picker as user 0 on display:%d", displayId);
814             return false;
815         }
816     }
817 
818     /**
819      * Generates a random string which consists of captial letters and numbers.
820      */
821     @SuppressLint("DefaultLocale")  // Should always have the same format regardless of locale
generateRandomAlphaNumericString(int length)822     public static String generateRandomAlphaNumericString(int length) {
823         StringBuilder sb = new StringBuilder();
824 
825         int poolSize = CHAR_POOL_FOR_RANDOM_STRING.length;
826         for (int i = 0; i < length; i++) {
827             sb.append(CHAR_POOL_FOR_RANDOM_STRING[ThreadLocalRandom.current().nextInt(poolSize)]);
828         }
829         return sb.toString();
830     }
831 
832     /**
833      * Encrypts byte array with the keys stored in {@code keyAlias} using AES.
834      *
835      * @return Encrypted data and initialization vector in {@link EncryptedData}. {@code null} in
836      *         case of errors.
837      */
838     @Nullable
encryptData(byte[] data, String keyAlias)839     public static EncryptedData encryptData(byte[] data, String keyAlias) {
840         SecretKey secretKey = getOrCreateSecretKey(keyAlias);
841         if (secretKey == null) {
842             Slogf.e(TAG, "Failed to encrypt data: cannot get a secret key (keyAlias: %s)",
843                     keyAlias);
844             return null;
845         }
846         try {
847             Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
848             cipher.init(Cipher.ENCRYPT_MODE, secretKey);
849             return new EncryptedData(cipher.doFinal(data), cipher.getIV());
850         } catch (Exception e) {
851             Slogf.e(TAG, e, "Failed to encrypt data: keyAlias=%s", keyAlias);
852             return null;
853         }
854     }
855 
856     /**
857      * Decrypts byte array with the keys stored in {@code keyAlias} using AES.
858      *
859      * @return Decrypted data in byte array. {@code null} in case of errors.
860      */
861     @Nullable
decryptData(EncryptedData data, String keyAlias)862     public static byte[] decryptData(EncryptedData data, String keyAlias) {
863         SecretKey secretKey = getOrCreateSecretKey(keyAlias);
864         if (secretKey == null) {
865             Slogf.e(TAG, "Failed to decrypt data: cannot get a secret key (keyAlias: %s)",
866                     keyAlias);
867             return null;
868         }
869         try {
870             Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
871             GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, data.getIv());
872             cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
873             return cipher.doFinal(data.getEncryptedData());
874         } catch (Exception e) {
875             Slogf.e(TAG, e, "Failed to decrypt data: keyAlias=%s", keyAlias);
876             return null;
877         }
878     }
879 
880     /**
881      * Class to hold encrypted data and its initialization vector.
882      */
883     public static final class EncryptedData {
884         private final byte[] mEncryptedData;
885         private final byte[] mIv;
886 
EncryptedData(byte[] encryptedData, byte[] iv)887         public EncryptedData(byte[] encryptedData, byte[] iv) {
888             mEncryptedData = encryptedData;
889             mIv = iv;
890         }
891 
getEncryptedData()892         public byte[] getEncryptedData() {
893             return mEncryptedData;
894         }
895 
getIv()896         public byte[] getIv() {
897             return mIv;
898         }
899 
900         @Override
equals(Object other)901         public boolean equals(Object other) {
902             if (this == other) return true;
903             if (!(other instanceof EncryptedData)) return false;
904             EncryptedData data = (EncryptedData) other;
905             return Arrays.equals(mEncryptedData, data.mEncryptedData)
906                     && Arrays.equals(mIv, data.mIv);
907         }
908 
909         @Override
hashCode()910         public int hashCode() {
911             return Objects.hash(Arrays.hashCode(mEncryptedData), Arrays.hashCode(mIv));
912         }
913     }
914 
915     @Nullable
getOrCreateSecretKey(String keyAlias)916     private static SecretKey getOrCreateSecretKey(String keyAlias) {
917         try {
918             KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE_NAME);
919             keyStore.load(/* KeyStore.LoadStoreParameter= */ null);
920             if (keyStore.containsAlias(keyAlias)) {
921                 SecretKeyEntry secretKeyEntry = (SecretKeyEntry) keyStore.getEntry(keyAlias,
922                         /* protParam= */ null);
923                 if (secretKeyEntry != null) {
924                     return secretKeyEntry.getSecretKey();
925                 }
926                 Slogf.e(TAG, "Android key store contains the alias (%s) but the secret key "
927                         + "entry is null", keyAlias);
928                 return null;
929             }
930             KeyGenerator keyGenerator = KeyGenerator.getInstance(
931                     KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE_NAME);
932             KeyGenParameterSpec keyGenParameterSpec =
933                     new KeyGenParameterSpec.Builder(keyAlias, KeyProperties.PURPOSE_ENCRYPT
934                             | KeyProperties.PURPOSE_DECRYPT)
935                     .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
936                     .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
937                     .build();
938             keyGenerator.init(keyGenParameterSpec);
939             return keyGenerator.generateKey();
940         } catch (Exception e) {
941             Slogf.e(TAG, "Failed to get or create a secret key for the alias (%s)", keyAlias);
942             return null;
943         }
944     }
945 }
946