• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 package com.android.car.util;
17 
18 import static android.car.user.CarUserManager.lifecycleEventTypeToString;
19 
20 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SuppressLint;
25 import android.annotation.UserIdInt;
26 import android.app.ActivityManager;
27 import android.car.builtin.util.Slogf;
28 import android.car.user.CarUserManager.UserLifecycleEvent;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.os.Binder;
33 import android.os.UserHandle;
34 
35 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
36 import com.android.car.internal.common.CommonConstants.UserLifecycleEventType;
37 
38 import java.io.ByteArrayOutputStream;
39 import java.io.IOException;
40 import java.nio.ByteBuffer;
41 import java.nio.ByteOrder;
42 import java.util.Arrays;
43 import java.util.UUID;
44 import java.util.concurrent.ThreadLocalRandom;
45 import java.util.stream.Collectors;
46 
47 /**
48  * Some potentially useful static methods.
49  */
50 public final class Utils {
51     static final Boolean DBG = false;
52     // https://developer.android.com/reference/java/util/UUID
53     private static final int UUID_LENGTH = 16;
54 
55     /**
56      * Returns a byte buffer corresponding to the passed long argument.
57      *
58      * @param primitive data to convert format.
59      */
longToBytes(long primitive)60     public static byte[] longToBytes(long primitive) {
61         ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
62         buffer.putLong(primitive);
63         return buffer.array();
64     }
65 
66     /**
67      * Returns a byte buffer corresponding to the passed long argument.
68      *
69      * @param array data to convert format.
70      */
bytesToLong(byte[] array)71     public static long bytesToLong(byte[] array) {
72         ByteBuffer buffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
73         buffer.put(array);
74         buffer.flip();
75         long value = buffer.getLong();
76         return value;
77     }
78 
79     /**
80      * Returns a String in Hex format that is formed from the bytes in the byte array
81      * Useful for debugging
82      *
83      * @param array the byte array
84      * @return the Hex string version of the input byte array
85      */
byteArrayToHexString(byte[] array)86     public static String byteArrayToHexString(byte[] array) {
87         StringBuilder sb = new StringBuilder(array.length * 2);
88         for (byte b : array) {
89             sb.append(String.format("%02x", b));
90         }
91         return sb.toString();
92     }
93 
94     /**
95      * Convert UUID to Big Endian byte array
96      *
97      * @param uuid UUID to convert
98      * @return the byte array representing the UUID
99      */
100     @NonNull
uuidToBytes(@onNull UUID uuid)101     public static byte[] uuidToBytes(@NonNull UUID uuid) {
102 
103         return ByteBuffer.allocate(UUID_LENGTH)
104                 .order(ByteOrder.BIG_ENDIAN)
105                 .putLong(uuid.getMostSignificantBits())
106                 .putLong(uuid.getLeastSignificantBits())
107                 .array();
108     }
109 
110     /**
111      * Convert Big Endian byte array to UUID
112      *
113      * @param bytes byte array to convert
114      * @return the UUID representing the byte array, or null if not a valid UUID
115      */
116     @Nullable
bytesToUUID(@onNull byte[] bytes)117     public static UUID bytesToUUID(@NonNull byte[] bytes) {
118         if (bytes.length != UUID_LENGTH) {
119             return null;
120         }
121 
122         ByteBuffer buffer = ByteBuffer.wrap(bytes);
123         return new UUID(buffer.getLong(), buffer.getLong());
124     }
125 
126     /**
127      * Generate a random zero-filled string of given length
128      *
129      * @param length of string
130      * @return generated string
131      */
132     @SuppressLint("DefaultLocale")  // Should always have the same format regardless of locale
generateRandomNumberString(int length)133     public static String generateRandomNumberString(int length) {
134         return String.format("%0" + length + "d",
135                 ThreadLocalRandom.current().nextInt((int) Math.pow(10, length)));
136     }
137 
138 
139     /**
140      * Concatentate the given 2 byte arrays
141      *
142      * @param a input array 1
143      * @param b input array 2
144      * @return concatenated array of arrays 1 and 2
145      */
146     @Nullable
concatByteArrays(@ullable byte[] a, @Nullable byte[] b)147     public static byte[] concatByteArrays(@Nullable byte[] a, @Nullable byte[] b) {
148         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
149         try {
150             if (a != null) {
151                 outputStream.write(a);
152             }
153             if (b != null) {
154                 outputStream.write(b);
155             }
156         } catch (IOException e) {
157             return null;
158         }
159         return outputStream.toByteArray();
160     }
161 
162     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE,
163             details = "private constructor")
Utils()164     private Utils() {
165         throw new UnsupportedOperationException("contains only static methods");
166     }
167 
168     /**
169      * Returns the content resolver for the given user. This can be used to put/get the
170      * user's settings.
171      *
172      * @param context The context of the package.
173      * @param userId The id of the user which the content resolver is being requested for. It also
174      * accepts {@link UserHandle#USER_CURRENT}.
175      */
getContentResolverForUser(Context context, @UserIdInt int userId)176     public static ContentResolver getContentResolverForUser(Context context,
177             @UserIdInt int userId) {
178         if (userId == UserHandle.CURRENT.getIdentifier()) {
179             userId = ActivityManager.getCurrentUser();
180         }
181         return context
182                 .createContextAsUser(
183                         UserHandle.of(userId), /* flags= */ 0)
184                 .getContentResolver();
185     }
186 
187     /**
188      * Checks if the type of the {@code event} matches {@code expectedType}.
189      *
190      * @param tag The tag for logging.
191      * @param event The event to check the type against {@code expectedType}.
192      * @param expectedType The expected event type.
193      * @return true if {@code event}'s type matches {@code expectedType}.
194      *         Otherwise, log a wtf and return false.
195      */
isEventOfType(String tag, UserLifecycleEvent event, @UserLifecycleEventType int expectedType)196     public static boolean isEventOfType(String tag, UserLifecycleEvent event,
197             @UserLifecycleEventType int expectedType) {
198         if (event.getEventType() == expectedType) {
199             return true;
200         }
201         Slogf.wtf(tag, "Received an unexpected event: %s. Expected type: %s.", event,
202                 lifecycleEventTypeToString(expectedType));
203         return false;
204     }
205 
206     /**
207      * Checks if the type of the {@code event} is one of the types in {@code expectedTypes}.
208      *
209      * @param tag The tag for logging.
210      * @param event The event to check the type against {@code expectedTypes}.
211      * @param expectedTypes The expected event types. Must not be empty.
212      * @return true if {@code event}'s type can be found in {@code expectedTypes}.
213      *         Otherwise, log a wtf and return false.
214      */
isEventAnyOfTypes(String tag, UserLifecycleEvent event, @UserLifecycleEventType int... expectedTypes)215     public static boolean isEventAnyOfTypes(String tag, UserLifecycleEvent event,
216             @UserLifecycleEventType int... expectedTypes) {
217         for (int i = 0; i < expectedTypes.length; i++) {
218             if (event.getEventType() == expectedTypes[i]) {
219                 return true;
220             }
221         }
222         Slogf.wtf(tag, "Received an unexpected event: %s. Expected types: [%s]", event,
223                 Arrays.stream(expectedTypes).mapToObj(t -> lifecycleEventTypeToString(t)).collect(
224                         Collectors.joining(",")));
225         return false;
226     }
227 
228     /**
229      * Checks if the calling UID owns the give package.
230      *
231      * @throws SecurityException if the calling UID doesn't own the given package.
232      */
checkCalledByPackage(Context context, String packageName)233     public static void checkCalledByPackage(Context context, String packageName) {
234         int callingUid = Binder.getCallingUid();
235         PackageManager pm = context.getPackageManager();
236         String[] packages = pm.getPackagesForUid(callingUid);
237         if (packages != null) {
238             for (String candidate: packages) {
239                 if (candidate.equals(packageName)) {
240                     return;
241                 }
242             }
243         }
244         throw new SecurityException(
245                 "Package " + packageName + " is not associated to UID " + callingUid);
246     }
247 
248 }
249