blob: c4f77cfdbb523d4d7f4507158f01a08a97d31db3 [file] [log] [blame]
keunyoungca515072015-07-10 12:21:47 -07001/*
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
17package com.android.car;
18
Keun-young Park4aeb4bf2015-12-08 18:31:33 -080019import android.content.Context;
20import android.content.pm.ApplicationInfo;
Keun-young Park4aeb4bf2015-12-08 18:31:33 -080021import android.content.pm.PackageManager.NameNotFoundException;
22import android.os.Binder;
Keun-young Park43cfff22016-02-19 12:49:52 -080023import android.os.Handler;
Keun young Parkb241d022020-04-20 20:31:34 -070024import android.os.HandlerThread;
Keun-young Park43cfff22016-02-19 12:49:52 -080025import android.os.Looper;
Keun young Park401479c2020-02-19 14:15:51 -080026import android.os.SystemClock;
Keun young Parkb241d022020-04-20 20:31:34 -070027import android.util.ArrayMap;
Eric Jeongbd5fb562020-12-21 13:49:40 -080028import android.util.Slog;
Keun-young Park4aeb4bf2015-12-08 18:31:33 -080029
Keun young Park1d076182020-05-21 09:40:59 -070030import com.android.internal.annotations.VisibleForTesting;
31
32import java.util.ArrayList;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070033import java.util.List;
34
keunyoungca515072015-07-10 12:21:47 -070035/** Utility class */
Keun-young Park43cfff22016-02-19 12:49:52 -080036public final class CarServiceUtils {
keunyoungca515072015-07-10 12:21:47 -070037
Mayank Garg72c71d22021-02-03 23:54:45 -080038 private static final String TAG = CarLog.tagFor(CarServiceUtils.class);
Keun young Park1fd33fe2019-12-19 18:25:14 -080039 /** Empty int array */
40 public static final int[] EMPTY_INT_ARRAY = new int[0];
41
Keun-young Park4aeb4bf2015-12-08 18:31:33 -080042 private static final String PACKAGE_NOT_FOUND = "Package not found:";
43
Keun young Parkb241d022020-04-20 20:31:34 -070044 /** K: class name, V: HandlerThread */
45 private static final ArrayMap<String, HandlerThread> sHandlerThreads = new ArrayMap<>();
46
Keun-young Park43cfff22016-02-19 12:49:52 -080047 /** do not construct. static only */
48 private CarServiceUtils() {};
49
Keun-young Park4aeb4bf2015-12-08 18:31:33 -080050 /**
51 * Check if package name passed belongs to UID for the current binder call.
52 * @param context
53 * @param packageName
54 */
Enrico Granata3da3c612017-01-20 15:24:30 -080055 public static void assertPackageName(Context context, String packageName)
Keun-young Park4aeb4bf2015-12-08 18:31:33 -080056 throws IllegalArgumentException, SecurityException {
57 if (packageName == null) {
58 throw new IllegalArgumentException("Package name null");
59 }
60 ApplicationInfo appInfo = null;
61 try {
62 appInfo = context.getPackageManager().getApplicationInfo(packageName,
63 0);
64 } catch (NameNotFoundException e) {
65 String msg = PACKAGE_NOT_FOUND + packageName;
Eric Jeongbd5fb562020-12-21 13:49:40 -080066 Slog.w(CarLog.TAG_SERVICE, msg, e);
Keun-young Park4aeb4bf2015-12-08 18:31:33 -080067 throw new SecurityException(msg, e);
68 }
69 if (appInfo == null) {
70 throw new SecurityException(PACKAGE_NOT_FOUND + packageName);
71 }
72 int uid = Binder.getCallingUid();
73 if (uid != appInfo.uid) {
74 throw new SecurityException("Wrong package name:" + packageName +
75 ", The package does not belong to caller's uid:" + uid);
76 }
77 }
Keun-young Park43cfff22016-02-19 12:49:52 -080078
79 /**
80 * Execute a runnable on the main thread
81 *
82 * @param action The code to run on the main thread.
83 */
84 public static void runOnMain(Runnable action) {
85 runOnLooper(Looper.getMainLooper(), action);
86 }
87
88 /**
89 * Execute a runnable in the given looper
90 * @param looper Looper to run the action.
91 * @param action The code to run.
92 */
93 public static void runOnLooper(Looper looper, Runnable action) {
94 new Handler(looper).post(action);
95 }
96
97 /**
98 * Execute a call on the application's main thread, blocking until it is
99 * complete. Useful for doing things that are not thread-safe, such as
100 * looking at or modifying the view hierarchy.
101 *
102 * @param action The code to run on the main thread.
103 */
104 public static void runOnMainSync(Runnable action) {
105 runOnLooperSync(Looper.getMainLooper(), action);
106 }
107
108 /**
109 * Execute a call on the given Looper thread, blocking until it is
110 * complete.
111 *
112 * @param looper Looper to run the action.
113 * @param action The code to run on the main thread.
114 */
115 public static void runOnLooperSync(Looper looper, Runnable action) {
116 if (Looper.myLooper() == looper) {
117 // requested thread is the same as the current thread. call directly.
118 action.run();
119 } else {
120 Handler handler = new Handler(looper);
121 SyncRunnable sr = new SyncRunnable(action);
122 handler.post(sr);
123 sr.waitForComplete();
124 }
125 }
126
127 private static final class SyncRunnable implements Runnable {
128 private final Runnable mTarget;
129 private volatile boolean mComplete = false;
130
131 public SyncRunnable(Runnable target) {
132 mTarget = target;
133 }
134
135 @Override
136 public void run() {
137 mTarget.run();
138 synchronized (this) {
139 mComplete = true;
140 notifyAll();
141 }
142 }
143
144 public void waitForComplete() {
145 synchronized (this) {
146 while (!mComplete) {
147 try {
148 wait();
149 } catch (InterruptedException e) {
150 }
151 }
152 }
153 }
154 }
Keun-young Park71b2f5c2016-03-10 18:44:40 -0800155
156 public static float[] toFloatArray(List<Float> list) {
Ashutosh Agarwal97433352021-10-04 18:14:58 +0000157 int size = list.size();
158 float[] array = new float[size];
159 for (int i = 0; i < size; ++i) {
160 array[i] = list.get(i);
161 }
162 return array;
163 }
164
165 public static long[] toLongArray(List<Long> list) {
166 int size = list.size();
167 long[] array = new long[size];
Keun-young Park71b2f5c2016-03-10 18:44:40 -0800168 for (int i = 0; i < size; ++i) {
169 array[i] = list.get(i);
170 }
171 return array;
172 }
173
174 public static int[] toIntArray(List<Integer> list) {
Ashutosh Agarwal97433352021-10-04 18:14:58 +0000175 int size = list.size();
176 int[] array = new int[size];
Keun-young Park71b2f5c2016-03-10 18:44:40 -0800177 for (int i = 0; i < size; ++i) {
178 array[i] = list.get(i);
179 }
180 return array;
181 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700182
183 public static byte[] toByteArray(List<Byte> list) {
Ashutosh Agarwal97433352021-10-04 18:14:58 +0000184 int size = list.size();
185 byte[] array = new byte[size];
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700186 for (int i = 0; i < size; ++i) {
187 array[i] = list.get(i);
188 }
189 return array;
190 }
Keun young Park401479c2020-02-19 14:15:51 -0800191
192 /**
193 * Returns delta between elapsed time to uptime = {@link SystemClock#elapsedRealtime()} -
194 * {@link SystemClock#uptimeMillis()}. Note that this value will be always >= 0.
195 */
196 public static long getUptimeToElapsedTimeDeltaInMillis() {
197 int retry = 0;
198 int max_retry = 2; // try only up to twice
199 while (true) {
200 long elapsed1 = SystemClock.elapsedRealtime();
201 long uptime = SystemClock.uptimeMillis();
202 long elapsed2 = SystemClock.elapsedRealtime();
203 if (elapsed1 == elapsed2) { // avoid possible 1 ms fluctuation.
204 return elapsed1 - uptime;
205 }
206 retry++;
207 if (retry >= max_retry) {
208 return elapsed1 - uptime;
209 }
210 }
211 }
Keun young Parkb241d022020-04-20 20:31:34 -0700212
213 /**
214 * Gets a static instance of {@code HandlerThread} for the given {@code name}. If the thread
215 * does not exist, create one and start it before returning.
216 */
217 public static HandlerThread getHandlerThread(String name) {
218 synchronized (sHandlerThreads) {
219 HandlerThread thread = sHandlerThreads.get(name);
Zhomart Mukhamejanove65a3392020-06-18 14:33:47 -0700220 if (thread == null || !thread.isAlive()) {
Eric Jeongbd5fb562020-12-21 13:49:40 -0800221 Slog.i(TAG, "Starting HandlerThread:" + name);
Keun young Parkb241d022020-04-20 20:31:34 -0700222 thread = new HandlerThread(name);
223 thread.start();
224 sHandlerThreads.put(name, thread);
225 }
226 return thread;
227 }
228 }
Keun young Park1d076182020-05-21 09:40:59 -0700229
230 /**
231 * Finishes all queued {@code Handler} tasks for {@code HandlerThread} created via
232 * {@link #getHandlerThread(String)}. This is useful only for testing.
233 */
234 @VisibleForTesting
235 public static void finishAllHandlerTasks() {
236 ArrayList<HandlerThread> threads;
237 synchronized (sHandlerThreads) {
238 threads = new ArrayList<>(sHandlerThreads.values());
239 }
240 ArrayList<SyncRunnable> syncs = new ArrayList<>(threads.size());
241 for (int i = 0; i < threads.size(); i++) {
242 Handler handler = new Handler(threads.get(i).getLooper());
243 SyncRunnable sr = new SyncRunnable(() -> { });
244 handler.post(sr);
245 syncs.add(sr);
246 }
247 for (int i = 0; i < syncs.size(); i++) {
248 syncs.get(i).waitForComplete();
249 }
250 }
keunyoungca515072015-07-10 12:21:47 -0700251}