blob: fcf1f14df162394bddc689fc26bf50f3e475004e [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;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070023import android.hardware.contexthub.V1_0.HubAppInfo;
24import android.hardware.contexthub.V1_0.IContexthub;
25import android.hardware.contexthub.V1_0.IContexthubCallback;
26import android.hardware.contexthub.V1_0.Result;
27import android.hardware.contexthub.V1_0.TransactionResult;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080028import android.hardware.location.ContextHubInfo;
Ashutosh Joshi420e45e2016-12-20 16:34:41 -080029import android.hardware.location.ContextHubMessage;
Arthur Ishiguroebb0e862017-11-17 14:55:32 -080030import android.hardware.location.ContextHubTransaction;
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 Ishiguroebb0e862017-11-17 14:55:32 -080040import android.hardware.location.NanoAppMessage;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070041import android.hardware.location.NanoAppState;
destradaa78cebca2016-04-14 18:40:14 -070042import android.os.RemoteCallbackList;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080043import android.os.RemoteException;
44import android.util.Log;
45
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060046import com.android.internal.util.DumpUtils;
47
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070048import java.io.FileDescriptor;
49import java.io.PrintWriter;
Ashutosh Joshi19753cc2016-11-23 13:56:39 -080050import java.nio.ByteBuffer;
51import java.nio.ByteOrder;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080052import java.util.ArrayList;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070053import java.util.Collections;
Arthur Ishiguroebb0e862017-11-17 14:55:32 -080054import java.util.HashMap;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070055import java.util.List;
Arthur Ishiguroebb0e862017-11-17 14:55:32 -080056import java.util.Map;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070057import java.util.NoSuchElementException;
Brian Duddiec3d8a522016-06-14 15:12:26 -070058import java.util.concurrent.ConcurrentHashMap;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080059
60/**
61 * @hide
62 */
Peng Xu9ff7d222016-02-11 13:02:05 -080063public class ContextHubService extends IContextHubService.Stub {
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080064 private static final String TAG = "ContextHubService";
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080065
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070066 /*
67 * Constants for the type of transaction that is defined by ContextHubService.
68 * This is used to report the transaction callback to clients, and is different from
69 * ContextHubTransaction.Type.
70 */
71 public static final int MSG_ENABLE_NANO_APP = 1;
72 public static final int MSG_DISABLE_NANO_APP = 2;
73 public static final int MSG_LOAD_NANO_APP = 3;
Ashutosh Joshicafdee92016-04-04 16:19:29 -070074 public static final int MSG_UNLOAD_NANO_APP = 4;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070075 public static final int MSG_QUERY_NANO_APPS = 5;
76 public static final int MSG_QUERY_MEMORY = 6;
77 public static final int MSG_HUB_RESET = 7;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070078
79 private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
80 private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
81 private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
82 private static final int PRE_LOADED_APP_MEM_REQ = 0;
83
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070084 private static final int OS_APP_INSTANCE = -1;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080085
Peng Xu9ff7d222016-02-11 13:02:05 -080086 private final Context mContext;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070087
88 // TODO(b/69270990): Remove once old ContextHubManager API is deprecated
89 // Service cache maintaining of instance ID to nanoapp infos
Brian Duddiec3d8a522016-06-14 15:12:26 -070090 private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
91 new ConcurrentHashMap<>();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070092 // The next available instance ID (managed by the service) to assign to a nanoapp
93 private int mNextAvailableInstanceId = 0;
94 // A map of the long nanoapp ID to instance ID managed by the service
95 private final ConcurrentHashMap<Long, Integer> mNanoAppIdToInstanceMap =
96 new ConcurrentHashMap<>();
97
destradaa78cebca2016-04-14 18:40:14 -070098 private final ContextHubInfo[] mContextHubInfo;
99 private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
100 new RemoteCallbackList<>();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800101
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700102 // Proxy object to communicate with the Context Hub HAL
103 private final IContexthub mContextHubProxy;
104
105 // The manager for transaction queue
106 private final ContextHubTransactionManager mTransactionManager;
107
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800108 // The manager for sending messages to/from clients
109 private final ContextHubClientManager mClientManager;
110
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800111 // The default client for old API clients
112 private final Map<Integer, IContextHubClient> mDefaultClientMap;
113
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700114 /**
115 * Class extending the callback to register with a Context Hub.
116 */
117 private class ContextHubServiceCallback extends IContexthubCallback.Stub {
118 private final int mContextHubId;
119
120 ContextHubServiceCallback(int contextHubId) {
121 mContextHubId = contextHubId;
122 }
123
124 @Override
125 public void handleClientMsg(ContextHubMsg message) {
126 handleClientMessageCallback(mContextHubId, message);
127 }
128
129 @Override
130 public void handleTxnResult(int transactionId, int result) {
131 handleTransactionResultCallback(mContextHubId, transactionId, result);
132 }
133
134 @Override
135 public void handleHubEvent(int eventType) {
136 handleHubEventCallback(mContextHubId, eventType);
137 }
138
139 @Override
140 public void handleAppAbort(long nanoAppId, int abortCode) {
141 handleAppAbortCallback(mContextHubId, nanoAppId, abortCode);
142 }
143
144 @Override
145 public void handleAppsInfo(ArrayList<HubAppInfo> nanoAppInfoList) {
146 handleQueryAppsCallback(mContextHubId, nanoAppInfoList);
147 }
148 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700149
Peng Xu9ff7d222016-02-11 13:02:05 -0800150 public ContextHubService(Context context) {
151 mContext = context;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700152
153 mContextHubProxy = getContextHubProxy();
154 if (mContextHubProxy == null) {
155 mTransactionManager = null;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800156 mClientManager = null;
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800157 mDefaultClientMap = Collections.EMPTY_MAP;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700158 mContextHubInfo = new ContextHubInfo[0];
159 return;
160 }
161
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800162 mClientManager = new ContextHubClientManager(mContext, mContextHubProxy);
Arthur Ishiguro0069f122017-11-20 15:07:14 -0800163 mTransactionManager = new ContextHubTransactionManager(mContextHubProxy, mClientManager);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700164
165 List<ContextHub> hubList;
166 try {
167 hubList = mContextHubProxy.getHubs();
168 } catch (RemoteException e) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800169 Log.e(TAG, "RemoteException while getting Context Hub info", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700170 hubList = Collections.emptyList();
171 }
172 mContextHubInfo = ContextHubServiceUtil.createContextHubInfoArray(hubList);
173
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800174 HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
175 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
176 int contextHubId = contextHubInfo.getId();
177
178 IContextHubClient client = mClientManager.registerClient(
179 createDefaultClientCallback(contextHubId), contextHubId);
180 defaultClientMap.put(contextHubId, client);
181 }
182 mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
183
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700184 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
185 int contextHubId = contextHubInfo.getId();
186 try {
187 mContextHubProxy.registerCallback(
188 contextHubId, new ContextHubServiceCallback(contextHubId));
189 } catch (RemoteException e) {
190 Log.e(TAG, "RemoteException while registering service callback for hub (ID = "
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800191 + contextHubId + ")", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700192 }
193 }
194
195 // Do a query to initialize the service cache list of nanoapps
196 // TODO(b/69270990): Remove this when old API is deprecated
197 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
198 queryNanoAppsInternal(contextHubInfo.getId());
199 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800200
201 for (int i = 0; i < mContextHubInfo.length; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700202 Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700203 + ", name: " + mContextHubInfo[i].getName());
Peng Xu9ff7d222016-02-11 13:02:05 -0800204 }
205 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800206
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700207 /**
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800208 * Creates a default client callback for old API clients.
209 *
210 * @param contextHubId the ID of the hub to attach this client to
211 * @return the internal callback interface
212 */
213 private IContextHubClientCallback createDefaultClientCallback(int contextHubId) {
214 return new IContextHubClientCallback.Stub() {
215 @Override
216 public void onMessageFromNanoApp(NanoAppMessage message) {
217 int nanoAppInstanceId =
218 mNanoAppIdToInstanceMap.containsKey(message.getNanoAppId()) ?
219 mNanoAppIdToInstanceMap.get(message.getNanoAppId()) : -1;
220
221 onMessageReceiptOldApi(
222 message.getMessageType(), contextHubId, nanoAppInstanceId,
223 message.getMessageBody());
224 }
225
226 @Override
227 public void onHubReset() {
Arthur Ishiguro6d47c542017-11-17 15:49:07 -0800228 byte[] data = {TransactionResult.SUCCESS};
229 onMessageReceiptOldApi(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800230 }
231
232 @Override
233 public void onNanoAppAborted(long nanoAppId, int abortCode) {
234 }
235
236 @Override
237 public void onNanoAppLoaded(long nanoAppId) {
238 }
239
240 @Override
241 public void onNanoAppUnloaded(long nanoAppId) {
242 }
243
244 @Override
245 public void onNanoAppEnabled(long nanoAppId) {
246 }
247
248 @Override
249 public void onNanoAppDisabled(long nanoAppId) {
250 }
251 };
252 }
253
254 /**
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700255 * @return the IContexthub proxy interface
256 */
257 private IContexthub getContextHubProxy() {
258 IContexthub proxy = null;
259 try {
260 proxy = IContexthub.getService(true /* retry */);
261 } catch (RemoteException e) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800262 Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700263 } catch (NoSuchElementException e) {
264 Log.i(TAG, "Context Hub HAL service not found");
265 }
266
267 return proxy;
268 }
269
Peng Xu9ff7d222016-02-11 13:02:05 -0800270 @Override
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700271 public int registerCallback(IContextHubCallback callback) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700272 checkPermissions();
destradaa78cebca2016-04-14 18:40:14 -0700273 mCallbacksList.register(callback);
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800274
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800275 Log.d(TAG, "Added callback, total callbacks " +
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700276 mCallbacksList.getRegisteredCallbackCount());
Peng Xu9ff7d222016-02-11 13:02:05 -0800277 return 0;
278 }
279
280 @Override
281 public int[] getContextHubHandles() throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700282 checkPermissions();
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700283 int[] returnArray = new int[mContextHubInfo.length];
Peng Xu9ff7d222016-02-11 13:02:05 -0800284
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800285 Log.d(TAG, "System supports " + returnArray.length + " hubs");
Peng Xu9ff7d222016-02-11 13:02:05 -0800286 for (int i = 0; i < returnArray.length; ++i) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700287 returnArray[i] = i;
Peng Xu9ff7d222016-02-11 13:02:05 -0800288 Log.d(TAG, String.format("Hub %s is mapped to %d",
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700289 mContextHubInfo[i].getName(), returnArray[i]));
Peng Xu9ff7d222016-02-11 13:02:05 -0800290 }
291
292 return returnArray;
293 }
294
295 @Override
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700296 public ContextHubInfo getContextHubInfo(int contextHubId) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700297 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700298 if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
299 Log.e(TAG, "Invalid context hub handle " + contextHubId);
Peng Xu9ff7d222016-02-11 13:02:05 -0800300 return null; // null means fail
301 }
302
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700303 return mContextHubInfo[contextHubId];
304 }
305
306 /**
307 * Creates an internal load transaction callback to be used for old API clients
308 *
309 * @param contextHubId the ID of the hub to load the binary
310 * @param nanoAppBinary the binary to load
311 * @return the callback interface
312 */
313 private IContextHubTransactionCallback createLoadTransactionCallback(
314 int contextHubId, NanoAppBinary nanoAppBinary) {
315 return new IContextHubTransactionCallback.Stub() {
316 @Override
317 public void onTransactionComplete(int result) {
318 handleLoadResponseOldApi(contextHubId, result, nanoAppBinary);
319 }
320
321 @Override
322 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
323 }
324 };
325 }
326
327 /**
328 * Creates an internal unload transaction callback to be used for old API clients
329 *
330 * @param contextHubId the ID of the hub to unload the nanoapp
331 * @param nanoAppId the ID of the nanoapp to unload
332 * @return the callback interface
333 */
334 private IContextHubTransactionCallback createUnloadTransactionCallback(
335 int contextHubId, long nanoAppId) {
336 return new IContextHubTransactionCallback.Stub() {
337 @Override
338 public void onTransactionComplete(int result) {
339 handleUnloadResponseOldApi(contextHubId, result, nanoAppId);
340 }
341
342 @Override
343 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
344 }
345 };
346 }
347
348 /**
349 * Creates an internal query transaction callback to be used for old API clients
350 *
351 * @param contextHubId the ID of the hub to query
352 * @return the callback interface
353 */
354 private IContextHubTransactionCallback createQueryTransactionCallback(int contextHubId) {
355 return new IContextHubTransactionCallback.Stub() {
356 @Override
357 public void onTransactionComplete(int result) {
358 }
359
360 @Override
361 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
362 byte[] data = {(byte) result};
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800363 onMessageReceiptOldApi(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700364 }
365 };
366 }
367
368 /**
369 * Adds a new transaction to the transaction manager queue
370 *
371 * @param transaction the transaction to add
372 * @return the result of adding the transaction
373 */
374 private int addTransaction(ContextHubServiceTransaction transaction) {
375 int result = Result.OK;
376 try {
377 mTransactionManager.addTransaction(transaction);
378 } catch (IllegalStateException e) {
379 Log.e(TAG, e.getMessage());
380 result = Result.TRANSACTION_PENDING; /* failed */
381 }
382
383 return result;
Peng Xu9ff7d222016-02-11 13:02:05 -0800384 }
385
386 @Override
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700387 public int loadNanoApp(int contextHubId, NanoApp app) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700388 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700389 if (mContextHubProxy == null) {
390 return -1;
391 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800392
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700393 if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
394 Log.e(TAG, "Invalid contextHubhandle " + contextHubId);
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700395 return -1;
Peng Xu9ff7d222016-02-11 13:02:05 -0800396 }
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600397 if (app == null) {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800398 Log.e(TAG, "Invalid null app");
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600399 return -1;
400 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800401
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700402 // Create an internal IContextHubTransactionCallback for the old API clients
403 NanoAppBinary nanoAppBinary = new NanoAppBinary(app.getAppBinary());
404 IContextHubTransactionCallback onCompleteCallback =
405 createLoadTransactionCallback(contextHubId, nanoAppBinary);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700406
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700407 ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
408 contextHubId, nanoAppBinary, onCompleteCallback);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700409
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700410 int result = addTransaction(transaction);
411 if (result != Result.OK) {
412 Log.e(TAG, "Failed to load nanoapp with error code " + result);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700413 return -1;
414 }
Ashutosh Joshi11864402016-07-15 13:46:22 -0700415
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700416 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
417 return 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800418 }
419
destradaa8bad3fe2016-03-15 12:33:40 -0700420 @Override
421 public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
422 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700423 if (mContextHubProxy == null) {
424 return -1;
425 }
426
Peng Xu9ff7d222016-02-11 13:02:05 -0800427 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
428 if (info == null) {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800429 Log.e(TAG, "Cannot find app with handle " + nanoAppInstanceHandle);
destradaa8bad3fe2016-03-15 12:33:40 -0700430 return -1; //means failed
Peng Xu9ff7d222016-02-11 13:02:05 -0800431 }
432
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700433 int contextHubId = info.getContexthubId();
434 long nanoAppId = info.getAppId();
435 IContextHubTransactionCallback onCompleteCallback =
436 createUnloadTransactionCallback(contextHubId, nanoAppId);
437 ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
438 contextHubId, nanoAppId, onCompleteCallback);
Peng Xu9ff7d222016-02-11 13:02:05 -0800439
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700440 int result = addTransaction(transaction);
441 if (result != Result.OK) {
442 Log.e(TAG, "Failed to unload nanoapp with error code " + result);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700443 return -1;
444 }
445
446 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
447 return 0;
destradaa8bad3fe2016-03-15 12:33:40 -0700448 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800449
450 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700451 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700452 throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700453 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800454 // This assumes that all the nanoAppInfo is current. This is reasonable
455 // for the use cases for tightly controlled nanoApps.
456 if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
457 return mNanoAppHash.get(nanoAppInstanceHandle);
458 } else {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800459 Log.e(TAG, "Could not find nanoApp with handle " + nanoAppInstanceHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800460 return null;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800461 }
462 }
463
464 @Override
Peng Xu9ff7d222016-02-11 13:02:05 -0800465 public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700466 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800467 ArrayList<Integer> foundInstances = new ArrayList<Integer>();
468
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700469 for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800470 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
471
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700472 if (filter.testMatch(info)) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800473 foundInstances.add(nanoAppInstance);
474 }
475 }
476
477 int[] retArray = new int[foundInstances.size()];
478 for (int i = 0; i < foundInstances.size(); i++) {
479 retArray[i] = foundInstances.get(i).intValue();
480 }
481
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800482 Log.w(TAG, "Found " + retArray.length + " apps on hub handle " + hubHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800483 return retArray;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800484 }
485
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700486 /**
487 * Performs a query at the specified hub.
488 *
489 * This method should only be invoked internally by the service, either to update the service
490 * cache or as a result of an explicit query requested by a client through the sendMessage API.
491 *
492 * @param contextHubId the ID of the hub to do the query
493 * @return the result of the query
494 */
495 private int queryNanoAppsInternal(int contextHubId) {
496 if (mContextHubProxy == null) {
497 return Result.UNKNOWN_FAILURE;
498 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700499
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700500 IContextHubTransactionCallback onCompleteCallback =
501 createQueryTransactionCallback(contextHubId);
502 ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
503 contextHubId, onCompleteCallback);
504
505 return addTransaction(transaction);
506 }
507
508 @Override
509 public int sendMessage(
510 int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
511 checkPermissions();
512 if (mContextHubProxy == null) {
513 return -1;
514 }
515 if (msg == null) {
516 Log.e(TAG, "ContextHubMessage cannot be null");
517 return -1;
518 }
519 if (msg.getData() == null) {
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800520 Log.e(TAG, "ContextHubMessage message body cannot be null");
521 return -1;
522 }
523 if (!mDefaultClientMap.containsKey(hubHandle)) {
524 Log.e(TAG, "Hub with ID " + hubHandle + " does not exist");
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600525 return -1;
526 }
527
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800528 boolean success = false;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700529 if (nanoAppHandle == OS_APP_INSTANCE) {
530 if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800531 success = (queryNanoAppsInternal(hubHandle) == Result.OK);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700532 } else {
533 Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType());
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700534 }
535 } else {
536 NanoAppInstanceInfo info = getNanoAppInstanceInfo(nanoAppHandle);
537 if (info != null) {
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800538 NanoAppMessage message = NanoAppMessage.createMessageToNanoApp(
539 info.getAppId(), msg.getMsgType(), msg.getData());
Peng Xu9ff7d222016-02-11 13:02:05 -0800540
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800541 IContextHubClient client = mDefaultClientMap.get(hubHandle);
542 success = (client.sendMessageToNanoApp(message) ==
543 ContextHubTransaction.TRANSACTION_SUCCESS);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700544 } else {
545 Log.e(TAG, "Failed to send nanoapp message - nanoapp with instance ID "
546 + nanoAppHandle + " does not exist.");
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700547 }
548 }
549
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800550 return success ? 0 : -1;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700551 }
552
553 /**
554 * Handles a unicast or broadcast message from a nanoapp.
555 *
556 * @param contextHubId the ID of the hub the message came from
557 * @param message the message contents
558 */
559 private void handleClientMessageCallback(int contextHubId, ContextHubMsg message) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800560 mClientManager.onMessageFromNanoApp(contextHubId, message);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700561 }
562
563 /**
564 * A helper function to handle a load response from the Context Hub for the old API.
565 *
566 * TODO(b/69270990): Remove this once the old APIs are obsolete.
567 */
568 private void handleLoadResponseOldApi(
569 int contextHubId, int result, NanoAppBinary nanoAppBinary) {
570 if (nanoAppBinary == null) {
571 Log.e(TAG, "Nanoapp binary field was null for a load transaction");
572 return;
573 }
574
575 // NOTE: The legacy JNI code used to do a query right after a load success
576 // to synchronize the service cache. Instead store the binary that was requested to
577 // load to update the cache later without doing a query.
578 int instanceId = 0;
579 long nanoAppId = nanoAppBinary.getNanoAppId();
580 int nanoAppVersion = nanoAppBinary.getNanoAppVersion();
581 if (result == TransactionResult.SUCCESS) {
582 if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
583 instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
584 } else {
585 instanceId = mNextAvailableInstanceId++;
586 mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
587 }
588
589 addAppInstance(contextHubId, instanceId, nanoAppId, nanoAppVersion);
590 }
591
592 byte[] data = new byte[5];
593 data[0] = (byte) result;
594 ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(instanceId);
595
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800596 onMessageReceiptOldApi(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700597 }
598
599 /**
600 * A helper function to handle an unload response from the Context Hub for the old API.
601 *
602 * TODO(b/69270990): Remove this once the old APIs are obsolete.
603 */
604 private void handleUnloadResponseOldApi(
605 int contextHubId, int result, long nanoAppId) {
606 if (result == TransactionResult.SUCCESS) {
607 int instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
608 deleteAppInstance(instanceId);
609 mNanoAppIdToInstanceMap.remove(nanoAppId);
610 }
611
612 byte[] data = new byte[1];
613 data[0] = (byte) result;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800614 onMessageReceiptOldApi(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700615 }
616
617 /**
618 * Handles a transaction response from a Context Hub.
619 *
620 * @param contextHubId the ID of the hub the response came from
621 * @param transactionId the ID of the transaction
622 * @param result the result of the transaction reported by the hub
623 */
624 private void handleTransactionResultCallback(int contextHubId, int transactionId, int result) {
625 mTransactionManager.onTransactionResponse(transactionId, result);
626 }
627
628 /**
629 * Handles an asynchronous event from a Context Hub.
630 *
631 * @param contextHubId the ID of the hub the response came from
632 * @param eventType the type of the event as defined in Context Hub HAL AsyncEventType
633 */
634 private void handleHubEventCallback(int contextHubId, int eventType) {
635 if (eventType == AsyncEventType.RESTARTED) {
636 mTransactionManager.onHubReset();
637 queryNanoAppsInternal(contextHubId);
638
Arthur Ishiguro6d47c542017-11-17 15:49:07 -0800639 mClientManager.onHubReset(contextHubId);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700640 } else {
641 Log.i(TAG, "Received unknown hub event (hub ID = " + contextHubId + ", type = "
642 + eventType + ")");
643 }
644 }
645
646 /**
647 * Handles an asynchronous abort event of a nanoapp.
648 *
649 * @param contextHubId the ID of the hub that the nanoapp aborted in
650 * @param nanoAppId the ID of the aborted nanoapp
651 * @param abortCode the nanoapp-specific abort code
652 */
653 private void handleAppAbortCallback(int contextHubId, long nanoAppId, int abortCode) {
654 // TODO(b/31049861): Implement this
655 }
656
657 /**
658 * Handles a query response from a Context Hub.
659 *
660 * @param contextHubId the ID of the hub of the response
661 * @param nanoAppInfoList the list of loaded nanoapps
662 */
663 private void handleQueryAppsCallback(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
664 List<NanoAppState> nanoAppStateList =
665 ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
666
667 updateServiceCache(contextHubId, nanoAppInfoList);
668 mTransactionManager.onQueryResponse(nanoAppStateList);
669 }
670
671 /**
672 * Updates the service's cache of the list of loaded nanoapps using a nanoapp list response.
673 *
674 * TODO(b/69270990): Remove this when the old API functionality is removed.
675 *
676 * @param contextHubId the ID of the hub the response came from
677 * @param nanoAppInfoList the list of loaded nanoapps
678 */
679 private void updateServiceCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
680 synchronized (mNanoAppHash) {
681 for (int instanceId : mNanoAppHash.keySet()) {
682 if (mNanoAppHash.get(instanceId).getContexthubId() == contextHubId) {
683 deleteAppInstance(instanceId);
684 }
685 }
686
687 for (HubAppInfo appInfo : nanoAppInfoList) {
688 int instanceId;
689 long nanoAppId = appInfo.appId;
690 if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
691 instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
692 } else {
693 instanceId = mNextAvailableInstanceId++;
694 mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
695 }
696
697 addAppInstance(contextHubId, instanceId, nanoAppId, appInfo.version);
698 }
699 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800700 }
destradaa8bad3fe2016-03-15 12:33:40 -0700701
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800702 /**
703 * @param contextHubId the hub ID to validate
704 * @return {@code true} if the ID represents that of an available hub, {@code false} otherwise
705 */
706 private boolean isValidContextHubId(int contextHubId) {
707 for (ContextHubInfo hubInfo : mContextHubInfo) {
708 if (hubInfo.getId() == contextHubId) {
709 return true;
710 }
711 }
712
713 return false;
714 }
715
716 /**
717 * Creates and registers a client at the service for the specified Context Hub.
718 *
719 * @param clientCallback the client interface to register with the service
720 * @param contextHubId the ID of the hub this client is attached to
721 * @return the generated client interface, null if registration was unsuccessful
722 *
723 * @throws IllegalArgumentException if contextHubId is not a valid ID
724 * @throws IllegalStateException if max number of clients have already registered
725 * @throws NullPointerException if clientCallback is null
726 */
727 @Override
728 public IContextHubClient createClient(
729 IContextHubClientCallback clientCallback, int contextHubId) throws RemoteException {
730 checkPermissions();
731 if (!isValidContextHubId(contextHubId)) {
732 throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
733 }
734 if (clientCallback == null) {
735 throw new NullPointerException("Cannot register client with null callback");
736 }
737
738 return mClientManager.registerClient(clientCallback, contextHubId);
739 }
740
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800741 /**
742 * Loads a nanoapp binary at the specified Context hub.
743 *
744 * @param contextHubId the ID of the hub to load the binary
745 * @param transactionCallback the client-facing transaction callback interface
746 * @param nanoAppBinary the binary to load
747 *
748 * @throws RemoteException
749 */
750 @Override
751 public void loadNanoAppOnHub(
752 int contextHubId, IContextHubTransactionCallback transactionCallback,
753 NanoAppBinary nanoAppBinary) throws RemoteException {
754 checkPermissions();
755 if (mContextHubProxy == null) {
756 transactionCallback.onTransactionComplete(
757 ContextHubTransaction.TRANSACTION_FAILED_HAL_UNAVAILABLE);
758 return;
759 }
760 if (!isValidContextHubId(contextHubId)) {
761 Log.e(TAG, "Cannot load nanoapp for invalid hub ID " + contextHubId);
762 transactionCallback.onTransactionComplete(
763 ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
764 return;
765 }
766 if (nanoAppBinary == null) {
767 Log.e(TAG, "NanoAppBinary cannot be null in loadNanoAppOnHub");
768 transactionCallback.onTransactionComplete(
769 ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
770 return;
771 }
772
773 ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
774 contextHubId, nanoAppBinary, transactionCallback);
775
776 addTransaction(transaction);
777 }
778
779 /**
780 * Unloads a nanoapp from the specified Context Hub.
781 *
782 * @param contextHubId the ID of the hub to unload the nanoapp
783 * @param transactionCallback the client-facing transaction callback interface
784 * @param nanoAppId the ID of the nanoapp to unload
785 *
786 * @throws RemoteException
787 */
788 @Override
789 public void unloadNanoAppFromHub(
790 int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId)
791 throws RemoteException {
792 checkPermissions();
793 if (mContextHubProxy == null) {
794 transactionCallback.onTransactionComplete(
795 ContextHubTransaction.TRANSACTION_FAILED_HAL_UNAVAILABLE);
796 return;
797 }
798 if (!isValidContextHubId(contextHubId)) {
799 Log.e(TAG, "Cannot unload nanoapp for invalid hub ID " + contextHubId);
800 transactionCallback.onTransactionComplete(
801 ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
802 return;
803 }
804
805 ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
806 contextHubId, nanoAppId, transactionCallback);
807
808 addTransaction(transaction);
809 }
810
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700811 @Override
812 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600813 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700814
815 pw.println("Dumping ContextHub Service");
816
817 pw.println("");
818 // dump ContextHubInfo
819 pw.println("=================== CONTEXT HUBS ====================");
820 for (int i = 0; i < mContextHubInfo.length; i++) {
821 pw.println("Handle " + i + " : " + mContextHubInfo[i].toString());
822 }
823 pw.println("");
824 pw.println("=================== NANOAPPS ====================");
825 // Dump nanoAppHash
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700826 for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700827 pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
828 }
829
830 // dump eventLog
831 }
832
destradaa8bad3fe2016-03-15 12:33:40 -0700833 private void checkPermissions() {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800834 ContextHubServiceUtil.checkPermissions(mContext);
destradaa8bad3fe2016-03-15 12:33:40 -0700835 }
Ashutosh Joshi2c697fb2016-04-01 20:48:13 +0000836
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800837 private int onMessageReceiptOldApi(int msgType, int hubHandle, int appInstance, byte[] data) {
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700838 if (data == null) {
839 return -1;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700840 }
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800841
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700842 int msgVersion = 0;
destradaa78cebca2016-04-14 18:40:14 -0700843 int callbacksCount = mCallbacksList.beginBroadcast();
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800844 Log.d(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle " +
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700845 hubHandle + ", appInstance " + appInstance + ", callBackCount " + callbacksCount);
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800846
destradaa78cebca2016-04-14 18:40:14 -0700847 if (callbacksCount < 1) {
848 Log.v(TAG, "No message callbacks registered.");
849 return 0;
850 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700851
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800852 ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
destradaa78cebca2016-04-14 18:40:14 -0700853 for (int i = 0; i < callbacksCount; ++i) {
854 IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
855 try {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800856 callback.onMessageReceipt(hubHandle, appInstance, msg);
destradaa78cebca2016-04-14 18:40:14 -0700857 } catch (RemoteException e) {
858 Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
859 continue;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700860 }
861 }
destradaa78cebca2016-04-14 18:40:14 -0700862 mCallbacksList.finishBroadcast();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700863 return 0;
864 }
865
866 private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
867 // App Id encodes vendor & version
868 NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
869
870 appInfo.setAppId(appId);
871 appInfo.setAppVersion(appVersion);
872 appInfo.setName(PRE_LOADED_APP_NAME);
873 appInfo.setContexthubId(hubHandle);
874 appInfo.setHandle(appInstanceHandle);
875 appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
876 appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
877 appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
878 appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
879
Greg Kaiserfe6d4f52016-08-19 10:24:07 -0700880 String action;
881 if (mNanoAppHash.containsKey(appInstanceHandle)) {
882 action = "Updated";
883 } else {
884 action = "Added";
885 }
886
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700887 mNanoAppHash.put(appInstanceHandle, appInfo);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700888 Log.d(TAG, action + " app instance " + appInstanceHandle + " with id 0x"
889 + Long.toHexString(appId) + " version 0x" + Integer.toHexString(appVersion));
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700890
891 return 0;
892 }
Brian Duddiec3d8a522016-06-14 15:12:26 -0700893
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700894 private int deleteAppInstance(int appInstanceHandle) {
895 if (mNanoAppHash.remove(appInstanceHandle) == null) {
896 return -1;
897 }
898
899 return 0;
900 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700901}