• 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 android.car.Car;
20 import android.car.builtin.util.Slogf;
21 import android.content.Context;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.PackageManager.NameNotFoundException;
25 import android.hardware.automotive.vehicle.SubscribeOptions;
26 import android.os.Binder;
27 import android.os.Handler;
28 import android.os.HandlerThread;
29 import android.os.Looper;
30 import android.os.Process;
31 import android.os.SystemClock;
32 import android.util.ArrayMap;
33 
34 import com.android.internal.annotations.VisibleForTesting;
35 
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.List;
39 
40 /** Utility class */
41 public final class CarServiceUtils {
42 
43     private static final String TAG = CarLog.tagFor(CarServiceUtils.class);
44     /** Empty int array */
45     public  static final int[] EMPTY_INT_ARRAY = new int[0];
46     private static final String COMMON_HANDLER_THREAD_NAME =
47             "CarServiceUtils_COMMON_HANDLER_THREAD";
48 
49     private static final String PACKAGE_NOT_FOUND = "Package not found:";
50 
51     /** K: class name, V: HandlerThread */
52     private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>();
53 
54     /** do not construct. static only */
CarServiceUtils()55     private CarServiceUtils() {}
56 
57     /**
58      * Check if package name passed belongs to UID for the current binder call.
59      * @param context
60      * @param packageName
61      */
assertPackageName(Context context, String packageName)62     public static void assertPackageName(Context context, String packageName)
63             throws IllegalArgumentException, SecurityException {
64         if (packageName == null) {
65             throw new IllegalArgumentException("Package name null");
66         }
67         ApplicationInfo appInfo = null;
68         try {
69             appInfo = context.getPackageManager().getApplicationInfo(packageName,
70                     0);
71         } catch (NameNotFoundException e) {
72             String msg = PACKAGE_NOT_FOUND + packageName;
73             Slogf.w(CarLog.TAG_SERVICE,  msg, e);
74             throw new SecurityException(msg, e);
75         }
76         if (appInfo == null) {
77             throw new SecurityException(PACKAGE_NOT_FOUND + packageName);
78         }
79         int uid = Binder.getCallingUid();
80         if (uid != appInfo.uid) {
81             throw new SecurityException("Wrong package name:" + packageName +
82                     ", The package does not belong to caller's uid:" + uid);
83         }
84     }
85 
86     /**
87      * Execute a runnable on the main thread
88      *
89      * @param action The code to run on the main thread.
90      */
runOnMain(Runnable action)91     public static void runOnMain(Runnable action) {
92         runOnLooper(Looper.getMainLooper(), action);
93     }
94 
95     /**
96      * Execute a runnable in the given looper
97      * @param looper Looper to run the action.
98      * @param action The code to run.
99      */
runOnLooper(Looper looper, Runnable action)100     public static void runOnLooper(Looper looper, Runnable action) {
101         new Handler(looper).post(action);
102     }
103 
104     /**
105      * Execute a call on the application's main thread, blocking until it is
106      * complete.  Useful for doing things that are not thread-safe, such as
107      * looking at or modifying the view hierarchy.
108      *
109      * @param action The code to run on the main thread.
110      */
runOnMainSync(Runnable action)111     public static void runOnMainSync(Runnable action) {
112         runOnLooperSync(Looper.getMainLooper(), action);
113     }
114 
115     /**
116      * Execute a delayed call on the application's main thread, blocking until it is
117      * complete. See {@link #runOnMainSync(Runnable)}
118      *
119      * @param action The code to run on the main thread.
120      * @param delayMillis The delay (in milliseconds) until the Runnable will be executed.
121      */
runOnMainSyncDelayed(Runnable action, long delayMillis)122     public static void runOnMainSyncDelayed(Runnable action, long delayMillis) {
123         runOnLooperSyncDelayed(Looper.getMainLooper(), action, delayMillis);
124     }
125 
126     /**
127      * Execute a call on the given Looper thread, blocking until it is
128      * complete.
129      *
130      * @param looper Looper to run the action.
131      * @param action The code to run on the looper thread.
132      */
runOnLooperSync(Looper looper, Runnable action)133     public static void runOnLooperSync(Looper looper, Runnable action) {
134         runOnLooperSyncDelayed(looper, action, /* delayMillis */ 0L);
135     }
136 
137     /**
138      * Executes a delayed call on the given Looper thread, blocking until it is complete.
139      *
140      * @param looper Looper to run the action.
141      * @param action The code to run on the looper thread.
142      * @param delayMillis The delay (in milliseconds) until the Runnable will be executed.
143      */
runOnLooperSyncDelayed(Looper looper, Runnable action, long delayMillis)144     public static void runOnLooperSyncDelayed(Looper looper, Runnable action, long delayMillis) {
145         if (Looper.myLooper() == looper) {
146             // requested thread is the same as the current thread. call directly.
147             action.run();
148         } else {
149             Handler handler = new Handler(looper);
150             SyncRunnable sr = new SyncRunnable(action);
151             handler.postDelayed(sr, delayMillis);
152             sr.waitForComplete();
153         }
154     }
155 
156     /**
157      * Executes a runnable on the common thread. Useful for doing any kind of asynchronous work
158      * across the car related code that doesn't need to be on the main thread.
159      *
160      * @param action The code to run on the common thread.
161      */
runOnCommon(Runnable action)162     public static void runOnCommon(Runnable action) {
163         runOnLooper(getCommonHandlerThread().getLooper(), action);
164     }
165 
166     private static final class SyncRunnable implements Runnable {
167         private final Runnable mTarget;
168         private volatile boolean mComplete = false;
169 
SyncRunnable(Runnable target)170         public SyncRunnable(Runnable target) {
171             mTarget = target;
172         }
173 
174         @Override
run()175         public void run() {
176             mTarget.run();
177             synchronized (this) {
178                 mComplete = true;
179                 notifyAll();
180             }
181         }
182 
waitForComplete()183         public void waitForComplete() {
184             synchronized (this) {
185                 while (!mComplete) {
186                     try {
187                         wait();
188                     } catch (InterruptedException e) {
189                     }
190                 }
191             }
192         }
193     }
194 
toFloatArray(List<Float> list)195     public static float[] toFloatArray(List<Float> list) {
196         int size = list.size();
197         float[] array = new float[size];
198         for (int i = 0; i < size; ++i) {
199             array[i] = list.get(i);
200         }
201         return array;
202     }
203 
toLongArray(List<Long> list)204     public static long[] toLongArray(List<Long> list) {
205         int size = list.size();
206         long[] array = new long[size];
207         for (int i = 0; i < size; ++i) {
208             array[i] = list.get(i);
209         }
210         return array;
211     }
212 
toIntArray(List<Integer> list)213     public static int[] toIntArray(List<Integer> list) {
214         int size = list.size();
215         int[] array = new int[size];
216         for (int i = 0; i < size; ++i) {
217             array[i] = list.get(i);
218         }
219         return array;
220     }
221 
toByteArray(List<Byte> list)222     public static byte[] toByteArray(List<Byte> list) {
223         int size = list.size();
224         byte[] array = new byte[size];
225         for (int i = 0; i < size; ++i) {
226             array[i] = list.get(i);
227         }
228         return array;
229     }
230 
231     /**
232      * Returns delta between elapsed time to uptime = {@link SystemClock#elapsedRealtime()} -
233      * {@link SystemClock#uptimeMillis()}. Note that this value will be always >= 0.
234      */
getUptimeToElapsedTimeDeltaInMillis()235     public static long getUptimeToElapsedTimeDeltaInMillis() {
236         int retry = 0;
237         int max_retry = 2; // try only up to twice
238         while (true) {
239             long elapsed1 = SystemClock.elapsedRealtime();
240             long uptime = SystemClock.uptimeMillis();
241             long elapsed2 = SystemClock.elapsedRealtime();
242             if (elapsed1 == elapsed2) { // avoid possible 1 ms fluctuation.
243                 return elapsed1 - uptime;
244             }
245             retry++;
246             if (retry >= max_retry) {
247                 return elapsed1 - uptime;
248             }
249         }
250     }
251 
252     /**
253      * Gets a static instance of {@code HandlerThread} for the given {@code name}. If the thread
254      * does not exist, create one and start it before returning.
255      */
getHandlerThread(String name)256     public static HandlerThread getHandlerThread(String name) {
257         synchronized (sHandlerThreads) {
258             HandlerThread thread = sHandlerThreads.get(name);
259             if (thread == null || !thread.isAlive()) {
260                 Slogf.i(TAG, "Starting HandlerThread:" + name);
261                 thread = new HandlerThread(name);
262                 thread.start();
263                 sHandlerThreads.put(name, thread);
264             }
265             return thread;
266         }
267     }
268 
269     /**
270      * Gets the static instance of the common {@code HandlerThread} meant to be used across
271      * CarService.
272      */
getCommonHandlerThread()273     public static HandlerThread getCommonHandlerThread() {
274         return getHandlerThread(COMMON_HANDLER_THREAD_NAME);
275     }
276 
277     /**
278      * Finishes all queued {@code Handler} tasks for {@code HandlerThread} created via
279      * {@link#getHandlerThread(String)}. This is useful only for testing.
280      */
281     @VisibleForTesting
finishAllHandlerTasks()282     public static void finishAllHandlerTasks() {
283         ArrayList<HandlerThread> threads;
284         synchronized (sHandlerThreads) {
285             threads = new ArrayList<>(sHandlerThreads.values());
286         }
287         ArrayList<SyncRunnable> syncs = new ArrayList<>(threads.size());
288         for (int i = 0; i < threads.size(); i++) {
289             if (!threads.get(i).isAlive()) {
290                 continue;
291             }
292             Handler handler = new Handler(threads.get(i).getLooper());
293             SyncRunnable sr = new SyncRunnable(() -> { });
294             if (handler.post(sr)) {
295                 // Track the threads only where SyncRunnable is posted successfully.
296                 syncs.add(sr);
297             }
298         }
299         for (int i = 0; i < syncs.size(); i++) {
300             syncs.get(i).waitForComplete();
301         }
302     }
303 
304     /**
305      * Assert if binder call is coming from system process like system server or if it is called
306      * from its own process even if it is not system. The latter can happen in test environment.
307      * Note that car service runs as system user but test like car service test will not.
308      */
assertCallingFromSystemProcessOrSelf()309     public static void assertCallingFromSystemProcessOrSelf() {
310         if (isCallingFromSystemProcessOrSelf()) {
311             throw new SecurityException("Only allowed from system or self");
312         }
313     }
314 
315     /**
316      * @return true if binder call is coming from system process like system server or if it is
317      * called from its own process even if it is not system.
318      */
isCallingFromSystemProcessOrSelf()319     public static boolean isCallingFromSystemProcessOrSelf() {
320         int uid = Binder.getCallingUid();
321         int pid = Binder.getCallingPid();
322         return uid != Process.SYSTEM_UID && pid != Process.myPid();
323     }
324 
325 
326     /** Utility for checking permission */
assertVehicleHalMockPermission(Context context)327     public static void assertVehicleHalMockPermission(Context context) {
328         assertPermission(context, Car.PERMISSION_MOCK_VEHICLE_HAL);
329     }
330 
331     /** Utility for checking permission */
assertNavigationManagerPermission(Context context)332     public static void assertNavigationManagerPermission(Context context) {
333         assertPermission(context, Car.PERMISSION_CAR_NAVIGATION_MANAGER);
334     }
335 
336     /** Utility for checking permission */
assertClusterManagerPermission(Context context)337     public static void assertClusterManagerPermission(Context context) {
338         assertPermission(context, Car.PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL);
339     }
340 
341     /** Utility for checking permission */
assertPowerPermission(Context context)342     public static void assertPowerPermission(Context context) {
343         assertPermission(context, Car.PERMISSION_CAR_POWER);
344     }
345 
346     /** Utility for checking permission */
assertProjectionPermission(Context context)347     public static void assertProjectionPermission(Context context) {
348         assertPermission(context, Car.PERMISSION_CAR_PROJECTION);
349     }
350 
351     /** Verify the calling context has the {@link Car#PERMISSION_CAR_PROJECTION_STATUS} */
assertProjectionStatusPermission(Context context)352     public static void assertProjectionStatusPermission(Context context) {
353         assertPermission(context, Car.PERMISSION_CAR_PROJECTION_STATUS);
354     }
355 
356     /** Utility for checking permission */
assertAnyDiagnosticPermission(Context context)357     public static void assertAnyDiagnosticPermission(Context context) {
358         assertAnyPermission(context,
359                 Car.PERMISSION_CAR_DIAGNOSTIC_READ_ALL,
360                 Car.PERMISSION_CAR_DIAGNOSTIC_CLEAR);
361     }
362 
363     /** Utility for checking permission */
assertDrivingStatePermission(Context context)364     public static void assertDrivingStatePermission(Context context) {
365         assertPermission(context, Car.PERMISSION_CAR_DRIVING_STATE);
366     }
367 
368     /**
369      * Verify the calling context has either {@link Car#PERMISSION_VMS_SUBSCRIBER} or
370      * {@link Car#PERMISSION_VMS_PUBLISHER}
371      */
assertAnyVmsPermission(Context context)372     public static void assertAnyVmsPermission(Context context) {
373         assertAnyPermission(context,
374                 Car.PERMISSION_VMS_SUBSCRIBER,
375                 Car.PERMISSION_VMS_PUBLISHER);
376     }
377 
378     /** Utility for checking permission */
assertVmsPublisherPermission(Context context)379     public static void assertVmsPublisherPermission(Context context) {
380         assertPermission(context, Car.PERMISSION_VMS_PUBLISHER);
381     }
382 
383     /** Utility for checking permission */
assertVmsSubscriberPermission(Context context)384     public static void assertVmsSubscriberPermission(Context context) {
385         assertPermission(context, Car.PERMISSION_VMS_SUBSCRIBER);
386     }
387 
388     /** Utility for checking permission */
assertPermission(Context context, String permission)389     public static void assertPermission(Context context, String permission) {
390         if (context.checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
391             throw new SecurityException("requires " + permission);
392         }
393     }
394 
395     /**
396      * Checks to see if the caller has a permission.
397      *
398      * @return boolean TRUE if caller has the permission.
399      */
hasPermission(Context context, String permission)400     public static boolean hasPermission(Context context, String permission) {
401         return context.checkCallingOrSelfPermission(permission)
402                 == PackageManager.PERMISSION_GRANTED;
403     }
404 
405     /** Utility for checking permission */
assertAnyPermission(Context context, String... permissions)406     public static void assertAnyPermission(Context context, String... permissions) {
407         for (String permission : permissions) {
408             if (context.checkCallingOrSelfPermission(permission)
409                     == PackageManager.PERMISSION_GRANTED) {
410                 return;
411             }
412         }
413         throw new SecurityException("requires any of " + Arrays.toString(permissions));
414     }
415 
416     /**
417      * Turns a {@code SubscribeOptions} to {@code
418      * android.hardware.automotive.vehicle.V2_0.SubscribeOptions}
419      */
subscribeOptionsToHidl( SubscribeOptions options)420     public static android.hardware.automotive.vehicle.V2_0.SubscribeOptions subscribeOptionsToHidl(
421             SubscribeOptions options) {
422         android.hardware.automotive.vehicle.V2_0.SubscribeOptions hidlOptions =
423                 new android.hardware.automotive.vehicle.V2_0.SubscribeOptions();
424         hidlOptions.propId = options.propId;
425         hidlOptions.sampleRate = options.sampleRate;
426         // HIDL backend requires flags to be set although it is not used any more.
427         hidlOptions.flags = android.hardware.automotive.vehicle.V2_0.SubscribeFlags.EVENTS_FROM_CAR;
428         // HIDL backend does not support area IDs, so we ignore options.areaId field.
429         return hidlOptions;
430     }
431 }
432