• 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 
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