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