blob: 45842a2988e47cad6e3465734be719709f66b089 [file] [log] [blame]
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -08001/*
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
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080017package com.android.server.location;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080018
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080019import android.content.Context;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070020import android.hardware.contexthub.V1_0.AsyncEventType;
21import android.hardware.contexthub.V1_0.ContextHub;
22import android.hardware.contexthub.V1_0.ContextHubMsg;
23import android.hardware.contexthub.V1_0.HostEndPoint;
24import android.hardware.contexthub.V1_0.HubAppInfo;
25import android.hardware.contexthub.V1_0.IContexthub;
26import android.hardware.contexthub.V1_0.IContexthubCallback;
27import android.hardware.contexthub.V1_0.Result;
28import android.hardware.contexthub.V1_0.TransactionResult;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080029import android.hardware.location.ContextHubInfo;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080030import android.hardware.location.ContextHubMessage;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080031import android.hardware.location.IContextHubCallback;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080032import android.hardware.location.IContextHubClient;
33import android.hardware.location.IContextHubClientCallback;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070034import android.hardware.location.IContextHubService;
35import android.hardware.location.IContextHubTransactionCallback;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080036import android.hardware.location.NanoApp;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070037import android.hardware.location.NanoAppBinary;
38import android.hardware.location.NanoAppFilter;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080039import android.hardware.location.NanoAppInstanceInfo;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070040import android.hardware.location.NanoAppState;
destradaa78cebca2016-04-14 18:40:14 -070041import android.os.RemoteCallbackList;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080042import android.os.RemoteException;
43import android.util.Log;
44
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060045import com.android.internal.util.DumpUtils;
46
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070047import java.io.FileDescriptor;
48import java.io.PrintWriter;
Ashutosh Joshi19753cc2016-11-23 13:56:39 -080049import java.nio.ByteBuffer;
50import java.nio.ByteOrder;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080051import java.util.ArrayList;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070052import java.util.Collections;
53import java.util.List;
54import java.util.NoSuchElementException;
Brian Duddiec3d8a522016-06-14 15:12:26 -070055import java.util.concurrent.ConcurrentHashMap;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080056
57/**
58 * @hide
59 */
Peng Xu9ff7d222016-02-11 13:02:05 -080060public class ContextHubService extends IContextHubService.Stub {
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080061 private static final String TAG = "ContextHubService";
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080062
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070063 /*
64 * Constants for the type of transaction that is defined by ContextHubService.
65 * This is used to report the transaction callback to clients, and is different from
66 * ContextHubTransaction.Type.
67 */
68 public static final int MSG_ENABLE_NANO_APP = 1;
69 public static final int MSG_DISABLE_NANO_APP = 2;
70 public static final int MSG_LOAD_NANO_APP = 3;
Ashutosh Joshicafdee92016-04-04 16:19:29 -070071 public static final int MSG_UNLOAD_NANO_APP = 4;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070072 public static final int MSG_QUERY_NANO_APPS = 5;
73 public static final int MSG_QUERY_MEMORY = 6;
74 public static final int MSG_HUB_RESET = 7;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070075
76 private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
77 private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
78 private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
79 private static final int PRE_LOADED_APP_MEM_REQ = 0;
80
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070081 private static final int OS_APP_INSTANCE = -1;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080082
Peng Xu9ff7d222016-02-11 13:02:05 -080083 private final Context mContext;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070084
85 // TODO(b/69270990): Remove once old ContextHubManager API is deprecated
86 // Service cache maintaining of instance ID to nanoapp infos
Brian Duddiec3d8a522016-06-14 15:12:26 -070087 private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
88 new ConcurrentHashMap<>();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070089 // The next available instance ID (managed by the service) to assign to a nanoapp
90 private int mNextAvailableInstanceId = 0;
91 // A map of the long nanoapp ID to instance ID managed by the service
92 private final ConcurrentHashMap<Long, Integer> mNanoAppIdToInstanceMap =
93 new ConcurrentHashMap<>();
94
destradaa78cebca2016-04-14 18:40:14 -070095 private final ContextHubInfo[] mContextHubInfo;
96 private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
97 new RemoteCallbackList<>();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080098
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070099 // Proxy object to communicate with the Context Hub HAL
100 private final IContexthub mContextHubProxy;
101
102 // The manager for transaction queue
103 private final ContextHubTransactionManager mTransactionManager;
104
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800105 // The manager for sending messages to/from clients
106 private final ContextHubClientManager mClientManager;
107
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700108 /**
109 * Class extending the callback to register with a Context Hub.
110 */
111 private class ContextHubServiceCallback extends IContexthubCallback.Stub {
112 private final int mContextHubId;
113
114 ContextHubServiceCallback(int contextHubId) {
115 mContextHubId = contextHubId;
116 }
117
118 @Override
119 public void handleClientMsg(ContextHubMsg message) {
120 handleClientMessageCallback(mContextHubId, message);
121 }
122
123 @Override
124 public void handleTxnResult(int transactionId, int result) {
125 handleTransactionResultCallback(mContextHubId, transactionId, result);
126 }
127
128 @Override
129 public void handleHubEvent(int eventType) {
130 handleHubEventCallback(mContextHubId, eventType);
131 }
132
133 @Override
134 public void handleAppAbort(long nanoAppId, int abortCode) {
135 handleAppAbortCallback(mContextHubId, nanoAppId, abortCode);
136 }
137
138 @Override
139 public void handleAppsInfo(ArrayList<HubAppInfo> nanoAppInfoList) {
140 handleQueryAppsCallback(mContextHubId, nanoAppInfoList);
141 }
142 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700143
Peng Xu9ff7d222016-02-11 13:02:05 -0800144 public ContextHubService(Context context) {
145 mContext = context;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700146
147 mContextHubProxy = getContextHubProxy();
148 if (mContextHubProxy == null) {
149 mTransactionManager = null;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800150 mClientManager = null;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700151 mContextHubInfo = new ContextHubInfo[0];
152 return;
153 }
154
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800155 mClientManager = new ContextHubClientManager(mContext, mContextHubProxy);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700156 mTransactionManager = new ContextHubTransactionManager(mContextHubProxy);
157
158 List<ContextHub> hubList;
159 try {
160 hubList = mContextHubProxy.getHubs();
161 } catch (RemoteException e) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800162 Log.e(TAG, "RemoteException while getting Context Hub info", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700163 hubList = Collections.emptyList();
164 }
165 mContextHubInfo = ContextHubServiceUtil.createContextHubInfoArray(hubList);
166
167 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
168 int contextHubId = contextHubInfo.getId();
169 try {
170 mContextHubProxy.registerCallback(
171 contextHubId, new ContextHubServiceCallback(contextHubId));
172 } catch (RemoteException e) {
173 Log.e(TAG, "RemoteException while registering service callback for hub (ID = "
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800174 + contextHubId + ")", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700175 }
176 }
177
178 // Do a query to initialize the service cache list of nanoapps
179 // TODO(b/69270990): Remove this when old API is deprecated
180 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
181 queryNanoAppsInternal(contextHubInfo.getId());
182 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800183
184 for (int i = 0; i < mContextHubInfo.length; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700185 Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700186 + ", name: " + mContextHubInfo[i].getName());
Peng Xu9ff7d222016-02-11 13:02:05 -0800187 }
188 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800189
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700190 /**
191 * @return the IContexthub proxy interface
192 */
193 private IContexthub getContextHubProxy() {
194 IContexthub proxy = null;
195 try {
196 proxy = IContexthub.getService(true /* retry */);
197 } catch (RemoteException e) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800198 Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700199 } catch (NoSuchElementException e) {
200 Log.i(TAG, "Context Hub HAL service not found");
201 }
202
203 return proxy;
204 }
205
Peng Xu9ff7d222016-02-11 13:02:05 -0800206 @Override
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700207 public int registerCallback(IContextHubCallback callback) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700208 checkPermissions();
destradaa78cebca2016-04-14 18:40:14 -0700209 mCallbacksList.register(callback);
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800210 Log.d(TAG, "Added callback, total callbacks " +
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700211 mCallbacksList.getRegisteredCallbackCount());
Peng Xu9ff7d222016-02-11 13:02:05 -0800212 return 0;
213 }
214
215 @Override
216 public int[] getContextHubHandles() throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700217 checkPermissions();
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700218 int[] returnArray = new int[mContextHubInfo.length];
Peng Xu9ff7d222016-02-11 13:02:05 -0800219
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800220 Log.d(TAG, "System supports " + returnArray.length + " hubs");
Peng Xu9ff7d222016-02-11 13:02:05 -0800221 for (int i = 0; i < returnArray.length; ++i) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700222 returnArray[i] = i;
Peng Xu9ff7d222016-02-11 13:02:05 -0800223 Log.d(TAG, String.format("Hub %s is mapped to %d",
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700224 mContextHubInfo[i].getName(), returnArray[i]));
Peng Xu9ff7d222016-02-11 13:02:05 -0800225 }
226
227 return returnArray;
228 }
229
230 @Override
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700231 public ContextHubInfo getContextHubInfo(int contextHubId) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700232 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700233 if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
234 Log.e(TAG, "Invalid context hub handle " + contextHubId);
Peng Xu9ff7d222016-02-11 13:02:05 -0800235 return null; // null means fail
236 }
237
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700238 return mContextHubInfo[contextHubId];
239 }
240
241 /**
242 * Creates an internal load transaction callback to be used for old API clients
243 *
244 * @param contextHubId the ID of the hub to load the binary
245 * @param nanoAppBinary the binary to load
246 * @return the callback interface
247 */
248 private IContextHubTransactionCallback createLoadTransactionCallback(
249 int contextHubId, NanoAppBinary nanoAppBinary) {
250 return new IContextHubTransactionCallback.Stub() {
251 @Override
252 public void onTransactionComplete(int result) {
253 handleLoadResponseOldApi(contextHubId, result, nanoAppBinary);
254 }
255
256 @Override
257 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
258 }
259 };
260 }
261
262 /**
263 * Creates an internal unload transaction callback to be used for old API clients
264 *
265 * @param contextHubId the ID of the hub to unload the nanoapp
266 * @param nanoAppId the ID of the nanoapp to unload
267 * @return the callback interface
268 */
269 private IContextHubTransactionCallback createUnloadTransactionCallback(
270 int contextHubId, long nanoAppId) {
271 return new IContextHubTransactionCallback.Stub() {
272 @Override
273 public void onTransactionComplete(int result) {
274 handleUnloadResponseOldApi(contextHubId, result, nanoAppId);
275 }
276
277 @Override
278 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
279 }
280 };
281 }
282
283 /**
284 * Creates an internal query transaction callback to be used for old API clients
285 *
286 * @param contextHubId the ID of the hub to query
287 * @return the callback interface
288 */
289 private IContextHubTransactionCallback createQueryTransactionCallback(int contextHubId) {
290 return new IContextHubTransactionCallback.Stub() {
291 @Override
292 public void onTransactionComplete(int result) {
293 }
294
295 @Override
296 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
297 byte[] data = {(byte) result};
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800298 onMessageReceiptOldApi(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700299 }
300 };
301 }
302
303 /**
304 * Adds a new transaction to the transaction manager queue
305 *
306 * @param transaction the transaction to add
307 * @return the result of adding the transaction
308 */
309 private int addTransaction(ContextHubServiceTransaction transaction) {
310 int result = Result.OK;
311 try {
312 mTransactionManager.addTransaction(transaction);
313 } catch (IllegalStateException e) {
314 Log.e(TAG, e.getMessage());
315 result = Result.TRANSACTION_PENDING; /* failed */
316 }
317
318 return result;
Peng Xu9ff7d222016-02-11 13:02:05 -0800319 }
320
321 @Override
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700322 public int loadNanoApp(int contextHubId, NanoApp app) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700323 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700324 if (mContextHubProxy == null) {
325 return -1;
326 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800327
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700328 if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
329 Log.e(TAG, "Invalid contextHubhandle " + contextHubId);
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700330 return -1;
Peng Xu9ff7d222016-02-11 13:02:05 -0800331 }
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600332 if (app == null) {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800333 Log.e(TAG, "Invalid null app");
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600334 return -1;
335 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800336
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700337 // Create an internal IContextHubTransactionCallback for the old API clients
338 NanoAppBinary nanoAppBinary = new NanoAppBinary(app.getAppBinary());
339 IContextHubTransactionCallback onCompleteCallback =
340 createLoadTransactionCallback(contextHubId, nanoAppBinary);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700341
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700342 ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
343 contextHubId, nanoAppBinary, onCompleteCallback);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700344
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700345 int result = addTransaction(transaction);
346 if (result != Result.OK) {
347 Log.e(TAG, "Failed to load nanoapp with error code " + result);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700348 return -1;
349 }
Ashutosh Joshi11864402016-07-15 13:46:22 -0700350
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700351 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
352 return 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800353 }
354
destradaa8bad3fe2016-03-15 12:33:40 -0700355 @Override
356 public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
357 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700358 if (mContextHubProxy == null) {
359 return -1;
360 }
361
Peng Xu9ff7d222016-02-11 13:02:05 -0800362 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
363 if (info == null) {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800364 Log.e(TAG, "Cannot find app with handle " + nanoAppInstanceHandle);
destradaa8bad3fe2016-03-15 12:33:40 -0700365 return -1; //means failed
Peng Xu9ff7d222016-02-11 13:02:05 -0800366 }
367
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700368 int contextHubId = info.getContexthubId();
369 long nanoAppId = info.getAppId();
370 IContextHubTransactionCallback onCompleteCallback =
371 createUnloadTransactionCallback(contextHubId, nanoAppId);
372 ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
373 contextHubId, nanoAppId, onCompleteCallback);
Peng Xu9ff7d222016-02-11 13:02:05 -0800374
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700375 int result = addTransaction(transaction);
376 if (result != Result.OK) {
377 Log.e(TAG, "Failed to unload nanoapp with error code " + result);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700378 return -1;
379 }
380
381 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
382 return 0;
destradaa8bad3fe2016-03-15 12:33:40 -0700383 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800384
385 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700386 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700387 throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700388 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800389 // This assumes that all the nanoAppInfo is current. This is reasonable
390 // for the use cases for tightly controlled nanoApps.
391 if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
392 return mNanoAppHash.get(nanoAppInstanceHandle);
393 } else {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800394 Log.e(TAG, "Could not find nanoApp with handle " + nanoAppInstanceHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800395 return null;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800396 }
397 }
398
399 @Override
Peng Xu9ff7d222016-02-11 13:02:05 -0800400 public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700401 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800402 ArrayList<Integer> foundInstances = new ArrayList<Integer>();
403
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700404 for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800405 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
406
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700407 if (filter.testMatch(info)) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800408 foundInstances.add(nanoAppInstance);
409 }
410 }
411
412 int[] retArray = new int[foundInstances.size()];
413 for (int i = 0; i < foundInstances.size(); i++) {
414 retArray[i] = foundInstances.get(i).intValue();
415 }
416
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800417 Log.w(TAG, "Found " + retArray.length + " apps on hub handle " + hubHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800418 return retArray;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800419 }
420
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700421 /**
422 * Performs a query at the specified hub.
423 *
424 * This method should only be invoked internally by the service, either to update the service
425 * cache or as a result of an explicit query requested by a client through the sendMessage API.
426 *
427 * @param contextHubId the ID of the hub to do the query
428 * @return the result of the query
429 */
430 private int queryNanoAppsInternal(int contextHubId) {
431 if (mContextHubProxy == null) {
432 return Result.UNKNOWN_FAILURE;
433 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700434
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700435 IContextHubTransactionCallback onCompleteCallback =
436 createQueryTransactionCallback(contextHubId);
437 ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
438 contextHubId, onCompleteCallback);
439
440 return addTransaction(transaction);
441 }
442
443 @Override
444 public int sendMessage(
445 int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
446 checkPermissions();
447 if (mContextHubProxy == null) {
448 return -1;
449 }
450 if (msg == null) {
451 Log.e(TAG, "ContextHubMessage cannot be null");
452 return -1;
453 }
454 if (msg.getData() == null) {
455 Log.w(TAG, "ContextHubMessage message body cannot be null");
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600456 return -1;
457 }
458
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700459 int result;
460 if (nanoAppHandle == OS_APP_INSTANCE) {
461 if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
462 result = queryNanoAppsInternal(hubHandle);
463 } else {
464 Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType());
465 result = Result.BAD_PARAMS;
466 }
467 } else {
468 NanoAppInstanceInfo info = getNanoAppInstanceInfo(nanoAppHandle);
469 if (info != null) {
470 ContextHubMsg hubMessage = new ContextHubMsg();
471 hubMessage.appName = info.getAppId();
472 hubMessage.msgType = msg.getMsgType();
473 hubMessage.hostEndPoint = HostEndPoint.UNSPECIFIED;
474 ContextHubServiceUtil.copyToByteArrayList(msg.getData(), hubMessage.msg);
Peng Xu9ff7d222016-02-11 13:02:05 -0800475
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700476 try {
477 result = mContextHubProxy.sendMessageToHub(hubHandle, hubMessage);
478 } catch (RemoteException e) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800479 Log.e(TAG, "Failed to send nanoapp message - RemoteException", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700480 result = Result.UNKNOWN_FAILURE;
481 }
482 } else {
483 Log.e(TAG, "Failed to send nanoapp message - nanoapp with instance ID "
484 + nanoAppHandle + " does not exist.");
485 result = Result.BAD_PARAMS;
486 }
487 }
488
489 return (result == Result.OK ? 0 : -1);
490 }
491
492 /**
493 * Handles a unicast or broadcast message from a nanoapp.
494 *
495 * @param contextHubId the ID of the hub the message came from
496 * @param message the message contents
497 */
498 private void handleClientMessageCallback(int contextHubId, ContextHubMsg message) {
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700499 byte[] data = ContextHubServiceUtil.createPrimitiveByteArray(message.msg);
500
501 int nanoAppInstanceId = mNanoAppIdToInstanceMap.containsKey(message.appName) ?
502 mNanoAppIdToInstanceMap.get(message.appName) : -1;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800503 onMessageReceiptOldApi(message.msgType, contextHubId, nanoAppInstanceId, data);
504
505 mClientManager.onMessageFromNanoApp(contextHubId, message);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700506 }
507
508 /**
509 * A helper function to handle a load response from the Context Hub for the old API.
510 *
511 * TODO(b/69270990): Remove this once the old APIs are obsolete.
512 */
513 private void handleLoadResponseOldApi(
514 int contextHubId, int result, NanoAppBinary nanoAppBinary) {
515 if (nanoAppBinary == null) {
516 Log.e(TAG, "Nanoapp binary field was null for a load transaction");
517 return;
518 }
519
520 // NOTE: The legacy JNI code used to do a query right after a load success
521 // to synchronize the service cache. Instead store the binary that was requested to
522 // load to update the cache later without doing a query.
523 int instanceId = 0;
524 long nanoAppId = nanoAppBinary.getNanoAppId();
525 int nanoAppVersion = nanoAppBinary.getNanoAppVersion();
526 if (result == TransactionResult.SUCCESS) {
527 if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
528 instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
529 } else {
530 instanceId = mNextAvailableInstanceId++;
531 mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
532 }
533
534 addAppInstance(contextHubId, instanceId, nanoAppId, nanoAppVersion);
535 }
536
537 byte[] data = new byte[5];
538 data[0] = (byte) result;
539 ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(instanceId);
540
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800541 onMessageReceiptOldApi(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700542 }
543
544 /**
545 * A helper function to handle an unload response from the Context Hub for the old API.
546 *
547 * TODO(b/69270990): Remove this once the old APIs are obsolete.
548 */
549 private void handleUnloadResponseOldApi(
550 int contextHubId, int result, long nanoAppId) {
551 if (result == TransactionResult.SUCCESS) {
552 int instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
553 deleteAppInstance(instanceId);
554 mNanoAppIdToInstanceMap.remove(nanoAppId);
555 }
556
557 byte[] data = new byte[1];
558 data[0] = (byte) result;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800559 onMessageReceiptOldApi(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700560 }
561
562 /**
563 * Handles a transaction response from a Context Hub.
564 *
565 * @param contextHubId the ID of the hub the response came from
566 * @param transactionId the ID of the transaction
567 * @param result the result of the transaction reported by the hub
568 */
569 private void handleTransactionResultCallback(int contextHubId, int transactionId, int result) {
570 mTransactionManager.onTransactionResponse(transactionId, result);
571 }
572
573 /**
574 * Handles an asynchronous event from a Context Hub.
575 *
576 * @param contextHubId the ID of the hub the response came from
577 * @param eventType the type of the event as defined in Context Hub HAL AsyncEventType
578 */
579 private void handleHubEventCallback(int contextHubId, int eventType) {
580 if (eventType == AsyncEventType.RESTARTED) {
581 mTransactionManager.onHubReset();
582 queryNanoAppsInternal(contextHubId);
583
584 byte[] data = {TransactionResult.SUCCESS};
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800585 onMessageReceiptOldApi(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700586 } else {
587 Log.i(TAG, "Received unknown hub event (hub ID = " + contextHubId + ", type = "
588 + eventType + ")");
589 }
590 }
591
592 /**
593 * Handles an asynchronous abort event of a nanoapp.
594 *
595 * @param contextHubId the ID of the hub that the nanoapp aborted in
596 * @param nanoAppId the ID of the aborted nanoapp
597 * @param abortCode the nanoapp-specific abort code
598 */
599 private void handleAppAbortCallback(int contextHubId, long nanoAppId, int abortCode) {
600 // TODO(b/31049861): Implement this
601 }
602
603 /**
604 * Handles a query response from a Context Hub.
605 *
606 * @param contextHubId the ID of the hub of the response
607 * @param nanoAppInfoList the list of loaded nanoapps
608 */
609 private void handleQueryAppsCallback(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
610 List<NanoAppState> nanoAppStateList =
611 ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
612
613 updateServiceCache(contextHubId, nanoAppInfoList);
614 mTransactionManager.onQueryResponse(nanoAppStateList);
615 }
616
617 /**
618 * Updates the service's cache of the list of loaded nanoapps using a nanoapp list response.
619 *
620 * TODO(b/69270990): Remove this when the old API functionality is removed.
621 *
622 * @param contextHubId the ID of the hub the response came from
623 * @param nanoAppInfoList the list of loaded nanoapps
624 */
625 private void updateServiceCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
626 synchronized (mNanoAppHash) {
627 for (int instanceId : mNanoAppHash.keySet()) {
628 if (mNanoAppHash.get(instanceId).getContexthubId() == contextHubId) {
629 deleteAppInstance(instanceId);
630 }
631 }
632
633 for (HubAppInfo appInfo : nanoAppInfoList) {
634 int instanceId;
635 long nanoAppId = appInfo.appId;
636 if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
637 instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
638 } else {
639 instanceId = mNextAvailableInstanceId++;
640 mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
641 }
642
643 addAppInstance(contextHubId, instanceId, nanoAppId, appInfo.version);
644 }
645 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800646 }
destradaa8bad3fe2016-03-15 12:33:40 -0700647
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800648 /**
649 * @param contextHubId the hub ID to validate
650 * @return {@code true} if the ID represents that of an available hub, {@code false} otherwise
651 */
652 private boolean isValidContextHubId(int contextHubId) {
653 for (ContextHubInfo hubInfo : mContextHubInfo) {
654 if (hubInfo.getId() == contextHubId) {
655 return true;
656 }
657 }
658
659 return false;
660 }
661
662 /**
663 * Creates and registers a client at the service for the specified Context Hub.
664 *
665 * @param clientCallback the client interface to register with the service
666 * @param contextHubId the ID of the hub this client is attached to
667 * @return the generated client interface, null if registration was unsuccessful
668 *
669 * @throws IllegalArgumentException if contextHubId is not a valid ID
670 * @throws IllegalStateException if max number of clients have already registered
671 * @throws NullPointerException if clientCallback is null
672 */
673 @Override
674 public IContextHubClient createClient(
675 IContextHubClientCallback clientCallback, int contextHubId) throws RemoteException {
676 checkPermissions();
677 if (!isValidContextHubId(contextHubId)) {
678 throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
679 }
680 if (clientCallback == null) {
681 throw new NullPointerException("Cannot register client with null callback");
682 }
683
684 return mClientManager.registerClient(clientCallback, contextHubId);
685 }
686
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700687 @Override
688 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600689 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700690
691 pw.println("Dumping ContextHub Service");
692
693 pw.println("");
694 // dump ContextHubInfo
695 pw.println("=================== CONTEXT HUBS ====================");
696 for (int i = 0; i < mContextHubInfo.length; i++) {
697 pw.println("Handle " + i + " : " + mContextHubInfo[i].toString());
698 }
699 pw.println("");
700 pw.println("=================== NANOAPPS ====================");
701 // Dump nanoAppHash
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700702 for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700703 pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
704 }
705
706 // dump eventLog
707 }
708
destradaa8bad3fe2016-03-15 12:33:40 -0700709 private void checkPermissions() {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800710 ContextHubServiceUtil.checkPermissions(mContext);
destradaa8bad3fe2016-03-15 12:33:40 -0700711 }
Ashutosh Joshi2c697fb2016-04-01 20:48:13 +0000712
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800713 private int onMessageReceiptOldApi(int msgType, int hubHandle, int appInstance, byte[] data) {
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700714 if (data == null) {
715 return -1;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700716 }
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800717
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700718 int msgVersion = 0;
destradaa78cebca2016-04-14 18:40:14 -0700719 int callbacksCount = mCallbacksList.beginBroadcast();
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800720 Log.d(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle " +
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700721 hubHandle + ", appInstance " + appInstance + ", callBackCount " + callbacksCount);
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800722
destradaa78cebca2016-04-14 18:40:14 -0700723 if (callbacksCount < 1) {
724 Log.v(TAG, "No message callbacks registered.");
725 return 0;
726 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700727
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800728 ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
destradaa78cebca2016-04-14 18:40:14 -0700729 for (int i = 0; i < callbacksCount; ++i) {
730 IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
731 try {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800732 callback.onMessageReceipt(hubHandle, appInstance, msg);
destradaa78cebca2016-04-14 18:40:14 -0700733 } catch (RemoteException e) {
734 Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
735 continue;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700736 }
737 }
destradaa78cebca2016-04-14 18:40:14 -0700738 mCallbacksList.finishBroadcast();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700739 return 0;
740 }
741
742 private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
743 // App Id encodes vendor & version
744 NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
745
746 appInfo.setAppId(appId);
747 appInfo.setAppVersion(appVersion);
748 appInfo.setName(PRE_LOADED_APP_NAME);
749 appInfo.setContexthubId(hubHandle);
750 appInfo.setHandle(appInstanceHandle);
751 appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
752 appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
753 appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
754 appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
755
Greg Kaiserfe6d4f52016-08-19 10:24:07 -0700756 String action;
757 if (mNanoAppHash.containsKey(appInstanceHandle)) {
758 action = "Updated";
759 } else {
760 action = "Added";
761 }
762
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700763 mNanoAppHash.put(appInstanceHandle, appInfo);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700764 Log.d(TAG, action + " app instance " + appInstanceHandle + " with id 0x"
765 + Long.toHexString(appId) + " version 0x" + Integer.toHexString(appVersion));
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700766
767 return 0;
768 }
Brian Duddiec3d8a522016-06-14 15:12:26 -0700769
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700770 private int deleteAppInstance(int appInstanceHandle) {
771 if (mNanoAppHash.remove(appInstanceHandle) == null) {
772 return -1;
773 }
774
775 return 0;
776 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700777}