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 java.util.List;
20 
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.os.Binder;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.util.Log;
29 
30 /** Utility class */
31 public final class CarServiceUtils {
32 
33     private static final String PACKAGE_NOT_FOUND = "Package not found:";
34 
35     /** do not construct. static only */
CarServiceUtils()36     private CarServiceUtils() {};
37 
38     /**
39      * Check if package name passed belongs to UID for the current binder call.
40      * @param context
41      * @param packageName
42      */
assertPakcageName(Context context, String packageName)43     public static void assertPakcageName(Context context, String packageName)
44             throws IllegalArgumentException, SecurityException {
45         if (packageName == null) {
46             throw new IllegalArgumentException("Package name null");
47         }
48         ApplicationInfo appInfo = null;
49         try {
50             appInfo = context.getPackageManager().getApplicationInfo(packageName,
51                     0);
52         } catch (NameNotFoundException e) {
53             String msg = PACKAGE_NOT_FOUND + packageName;
54             Log.w(CarLog.TAG_SERVICE, msg, e);
55             throw new SecurityException(msg, e);
56         }
57         if (appInfo == null) {
58             throw new SecurityException(PACKAGE_NOT_FOUND + packageName);
59         }
60         int uid = Binder.getCallingUid();
61         if (uid != appInfo.uid) {
62             throw new SecurityException("Wrong package name:" + packageName +
63                     ", The package does not belong to caller's uid:" + uid);
64         }
65     }
66 
67     /**
68      * Execute a runnable on the main thread
69      *
70      * @param action The code to run on the main thread.
71      */
runOnMain(Runnable action)72     public static void runOnMain(Runnable action) {
73         runOnLooper(Looper.getMainLooper(), action);
74     }
75 
76     /**
77      * Execute a runnable in the given looper
78      * @param looper Looper to run the action.
79      * @param action The code to run.
80      */
runOnLooper(Looper looper, Runnable action)81     public static void runOnLooper(Looper looper, Runnable action) {
82         new Handler(looper).post(action);
83     }
84 
85     /**
86      * Execute a call on the application's main thread, blocking until it is
87      * complete.  Useful for doing things that are not thread-safe, such as
88      * looking at or modifying the view hierarchy.
89      *
90      * @param action The code to run on the main thread.
91      */
runOnMainSync(Runnable action)92     public static void runOnMainSync(Runnable action) {
93         runOnLooperSync(Looper.getMainLooper(), action);
94     }
95 
96     /**
97      * Execute a call on the given Looper thread, blocking until it is
98      * complete.
99      *
100      * @param looper Looper to run the action.
101      * @param action The code to run on the main thread.
102      */
runOnLooperSync(Looper looper, Runnable action)103     public static void runOnLooperSync(Looper looper, Runnable action) {
104         if (Looper.myLooper() == looper) {
105             // requested thread is the same as the current thread. call directly.
106             action.run();
107         } else {
108             Handler handler = new Handler(looper);
109             SyncRunnable sr = new SyncRunnable(action);
110             handler.post(sr);
111             sr.waitForComplete();
112         }
113     }
114 
115     private static final class SyncRunnable implements Runnable {
116         private final Runnable mTarget;
117         private volatile boolean mComplete = false;
118 
SyncRunnable(Runnable target)119         public SyncRunnable(Runnable target) {
120             mTarget = target;
121         }
122 
123         @Override
run()124         public void run() {
125             mTarget.run();
126             synchronized (this) {
127                 mComplete = true;
128                 notifyAll();
129             }
130         }
131 
waitForComplete()132         public void waitForComplete() {
133             synchronized (this) {
134                 while (!mComplete) {
135                     try {
136                         wait();
137                     } catch (InterruptedException e) {
138                     }
139                 }
140             }
141         }
142     }
143 
toFloatArray(List<Float> list)144     public static float[] toFloatArray(List<Float> list) {
145         final int size = list.size();
146         final float[] array = new float[size];
147         for (int i = 0; i < size; ++i) {
148             array[i] = list.get(i);
149         }
150         return array;
151     }
152 
toIntArray(List<Integer> list)153     public static int[] toIntArray(List<Integer> list) {
154         final int size = list.size();
155         final int[] array = new int[size];
156         for (int i = 0; i < size; ++i) {
157             array[i] = list.get(i);
158         }
159         return array;
160     }
161 }
162