• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.server.location;
18 
19 import android.Manifest;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.hardware.location.ContextHubInfo;
23 import android.hardware.location.ContextHubManager;
24 import android.hardware.location.ContextHubMessage;
25 import android.hardware.location.IContextHubService;
26 import android.hardware.location.IContextHubCallback;
27 import android.hardware.location.NanoAppFilter;
28 import android.hardware.location.NanoApp;
29 import android.hardware.location.NanoAppInstanceInfo;
30 import android.os.RemoteCallbackList;
31 import android.os.RemoteException;
32 import android.util.Log;
33 
34 import com.android.internal.util.DumpUtils;
35 
36 import java.io.FileDescriptor;
37 import java.io.PrintWriter;
38 import java.nio.ByteBuffer;
39 import java.nio.ByteOrder;
40 import java.util.ArrayList;
41 import java.util.concurrent.ConcurrentHashMap;
42 import java.util.HashMap;
43 
44 /**
45  * @hide
46  */
47 public class ContextHubService extends IContextHubService.Stub {
48     private static final String TAG = "ContextHubService";
49     private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
50     private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
51         + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
52 
53     public static final int ANY_HUB             = -1;
54     public static final int MSG_LOAD_NANO_APP   = 3;
55     public static final int MSG_UNLOAD_NANO_APP = 4;
56 
57     private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
58     private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
59     private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
60     private static final int PRE_LOADED_APP_MEM_REQ = 0;
61 
62     private static final int MSG_HEADER_SIZE = 4;
63     private static final int HEADER_FIELD_MSG_TYPE = 0;
64     private static final int HEADER_FIELD_MSG_VERSION = 1;
65     private static final int HEADER_FIELD_HUB_HANDLE = 2;
66     private static final int HEADER_FIELD_APP_INSTANCE = 3;
67 
68     private static final int HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
69     private static final int HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
70     private static final int MSG_LOAD_APP_HEADER_SIZE = MSG_HEADER_SIZE + 2;
71 
72     private static final int OS_APP_INSTANCE = -1;
73 
74     private final Context mContext;
75     private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
76             new ConcurrentHashMap<>();
77     private final ContextHubInfo[] mContextHubInfo;
78     private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
79             new RemoteCallbackList<>();
80 
nativeSendMessage(int[] header, byte[] data)81     private native int nativeSendMessage(int[] header, byte[] data);
nativeInitialize()82     private native ContextHubInfo[] nativeInitialize();
83 
ContextHubService(Context context)84     public ContextHubService(Context context) {
85         mContext = context;
86         mContextHubInfo = nativeInitialize();
87 
88         for (int i = 0; i < mContextHubInfo.length; i++) {
89             Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
90                   + ", name:  " + mContextHubInfo[i].getName());
91         }
92     }
93 
94     @Override
registerCallback(IContextHubCallback callback)95     public int registerCallback(IContextHubCallback callback) throws RemoteException {
96         checkPermissions();
97         mCallbacksList.register(callback);
98         Log.d(TAG, "Added callback, total callbacks " +
99               mCallbacksList.getRegisteredCallbackCount());
100         return 0;
101     }
102 
103     @Override
getContextHubHandles()104     public int[] getContextHubHandles() throws RemoteException {
105         checkPermissions();
106         int[] returnArray = new int[mContextHubInfo.length];
107 
108         Log.d(TAG, "System supports " + returnArray.length + " hubs");
109         for (int i = 0; i < returnArray.length; ++i) {
110             returnArray[i] = i;
111             Log.d(TAG, String.format("Hub %s is mapped to %d",
112                                      mContextHubInfo[i].getName(), returnArray[i]));
113         }
114 
115         return returnArray;
116     }
117 
118     @Override
getContextHubInfo(int contextHubHandle)119     public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
120         checkPermissions();
121         if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
122             Log.e(TAG, "Invalid context hub handle " + contextHubHandle);
123             return null; // null means fail
124         }
125 
126         return mContextHubInfo[contextHubHandle];
127     }
128 
129     @Override
loadNanoApp(int contextHubHandle, NanoApp app)130     public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
131         checkPermissions();
132 
133         if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
134             Log.e(TAG, "Invalid contextHubhandle " + contextHubHandle);
135             return -1;
136         }
137         if (app == null) {
138             Log.e(TAG, "Invalid null app");
139             return -1;
140         }
141 
142         int[] msgHeader = new int[MSG_LOAD_APP_HEADER_SIZE];
143         msgHeader[HEADER_FIELD_HUB_HANDLE] = contextHubHandle;
144         msgHeader[HEADER_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
145         msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
146         msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
147 
148         long appId = app.getAppId();
149 
150         msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
151         msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
152 
153         int errVal = nativeSendMessage(msgHeader, app.getAppBinary());
154         if (errVal != 0) {
155             Log.e(TAG, "Send Message returns error" + contextHubHandle);
156             return -1;
157         }
158 
159         // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
160         return 0;
161     }
162 
163     @Override
unloadNanoApp(int nanoAppInstanceHandle)164     public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
165         checkPermissions();
166         NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
167         if (info == null) {
168             Log.e(TAG, "Cannot find app with handle " + nanoAppInstanceHandle);
169             return -1; //means failed
170         }
171 
172         // Call Native interface here
173         int[] msgHeader = new int[MSG_HEADER_SIZE];
174         msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
175         msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppInstanceHandle;
176         msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
177         msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_UNLOAD_NANO_APP;
178 
179         byte msg[] = new byte[0];
180 
181         if (nativeSendMessage(msgHeader, msg) != 0) {
182             Log.e(TAG, "native send message fails");
183             return -1;
184         }
185 
186         // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
187         return 0;
188     }
189 
190     @Override
getNanoAppInstanceInfo(int nanoAppInstanceHandle)191     public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
192                                                       throws RemoteException {
193         checkPermissions();
194         // This assumes that all the nanoAppInfo is current. This is reasonable
195         // for the use cases for tightly controlled nanoApps.
196         if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
197             return mNanoAppHash.get(nanoAppInstanceHandle);
198         } else {
199             Log.e(TAG, "Could not find nanoApp with handle " + nanoAppInstanceHandle);
200             return null;
201         }
202     }
203 
204     @Override
findNanoAppOnHub(int hubHandle, NanoAppFilter filter)205     public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
206         checkPermissions();
207         ArrayList<Integer> foundInstances = new ArrayList<Integer>();
208 
209         for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
210             NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
211 
212             if (filter.testMatch(info)) {
213                 foundInstances.add(nanoAppInstance);
214             }
215         }
216 
217         int[] retArray = new int[foundInstances.size()];
218         for (int i = 0; i < foundInstances.size(); i++) {
219             retArray[i] = foundInstances.get(i).intValue();
220         }
221 
222         Log.w(TAG, "Found " + retArray.length + " apps on hub handle " + hubHandle);
223         return retArray;
224     }
225 
226     @Override
sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)227     public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
228                            throws RemoteException {
229         checkPermissions();
230 
231         if (msg == null || msg.getData() == null) {
232             Log.w(TAG, "null ptr");
233             return -1;
234         }
235 
236         int[] msgHeader = new int[MSG_HEADER_SIZE];
237         msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
238         msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppHandle;
239         msgHeader[HEADER_FIELD_MSG_VERSION] = msg.getVersion();
240         msgHeader[HEADER_FIELD_MSG_TYPE] = msg.getMsgType();
241 
242         return nativeSendMessage(msgHeader, msg.getData());
243     }
244 
245     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)246     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
247         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
248 
249         pw.println("Dumping ContextHub Service");
250 
251         pw.println("");
252         // dump ContextHubInfo
253         pw.println("=================== CONTEXT HUBS ====================");
254         for (int i = 0; i < mContextHubInfo.length; i++) {
255             pw.println("Handle " + i + " : " + mContextHubInfo[i].toString());
256         }
257         pw.println("");
258         pw.println("=================== NANOAPPS ====================");
259         // Dump nanoAppHash
260         for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
261             pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
262         }
263 
264         // dump eventLog
265     }
266 
checkPermissions()267     private void checkPermissions() {
268         mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
269     }
270 
onMessageReceipt(int[] header, byte[] data)271     private int onMessageReceipt(int[] header, byte[] data) {
272         if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
273             return  -1;
274         }
275 
276         int callbacksCount = mCallbacksList.beginBroadcast();
277         int msgType = header[HEADER_FIELD_MSG_TYPE];
278         int msgVersion = header[HEADER_FIELD_MSG_VERSION];
279         int hubHandle = header[HEADER_FIELD_HUB_HANDLE];
280         int appInstance = header[HEADER_FIELD_APP_INSTANCE];
281 
282         Log.d(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle " +
283               hubHandle + ", appInstance " + appInstance + ", callBackCount " + callbacksCount);
284 
285         if (callbacksCount < 1) {
286             Log.v(TAG, "No message callbacks registered.");
287             return 0;
288         }
289 
290         ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
291         for (int i = 0; i < callbacksCount; ++i) {
292             IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
293             try {
294                 callback.onMessageReceipt(hubHandle, appInstance, msg);
295             } catch (RemoteException e) {
296                 Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
297                 continue;
298             }
299         }
300         mCallbacksList.finishBroadcast();
301         return 0;
302     }
303 
addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion)304     private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
305         // App Id encodes vendor & version
306         NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
307 
308         appInfo.setAppId(appId);
309         appInfo.setAppVersion(appVersion);
310         appInfo.setName(PRE_LOADED_APP_NAME);
311         appInfo.setContexthubId(hubHandle);
312         appInfo.setHandle(appInstanceHandle);
313         appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
314         appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
315         appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
316         appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
317 
318         String action;
319         if (mNanoAppHash.containsKey(appInstanceHandle)) {
320             action = "Updated";
321         } else {
322             action = "Added";
323         }
324 
325         mNanoAppHash.put(appInstanceHandle, appInfo);
326         Log.d(TAG, action + " app instance " + appInstanceHandle + " with id "
327               + appId + " version " + appVersion);
328 
329         return 0;
330     }
331 
deleteAppInstance(int appInstanceHandle)332     private int deleteAppInstance(int appInstanceHandle) {
333         if (mNanoAppHash.remove(appInstanceHandle) == null) {
334             return -1;
335         }
336 
337         return 0;
338     }
339 }
340