blob: 90c912a5aee43a35e5556dc2790acdf2780ba53e [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;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080058
59/**
60 * @hide
61 */
Peng Xu9ff7d222016-02-11 13:02:05 -080062public class ContextHubService extends IContextHubService.Stub {
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080063 private static final String TAG = "ContextHubService";
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080064
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070065 /*
66 * Constants for the type of transaction that is defined by ContextHubService.
67 * This is used to report the transaction callback to clients, and is different from
68 * ContextHubTransaction.Type.
69 */
70 public static final int MSG_ENABLE_NANO_APP = 1;
71 public static final int MSG_DISABLE_NANO_APP = 2;
72 public static final int MSG_LOAD_NANO_APP = 3;
Ashutosh Joshicafdee92016-04-04 16:19:29 -070073 public static final int MSG_UNLOAD_NANO_APP = 4;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070074 public static final int MSG_QUERY_NANO_APPS = 5;
75 public static final int MSG_QUERY_MEMORY = 6;
76 public static final int MSG_HUB_RESET = 7;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070077
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070078 private static final int OS_APP_INSTANCE = -1;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080079
Peng Xu9ff7d222016-02-11 13:02:05 -080080 private final Context mContext;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070081
destradaa78cebca2016-04-14 18:40:14 -070082 private final ContextHubInfo[] mContextHubInfo;
83 private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
84 new RemoteCallbackList<>();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080085
Arthur Ishiguro7a23a962017-11-01 10:52:28 -070086 // Proxy object to communicate with the Context Hub HAL
87 private final IContexthub mContextHubProxy;
88
89 // The manager for transaction queue
90 private final ContextHubTransactionManager mTransactionManager;
91
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080092 // The manager for sending messages to/from clients
93 private final ContextHubClientManager mClientManager;
94
Arthur Ishiguroebb0e862017-11-17 14:55:32 -080095 // The default client for old API clients
96 private final Map<Integer, IContextHubClient> mDefaultClientMap;
97
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -080098 // The manager for the internal nanoapp state cache
99 private final NanoAppStateManager mNanoAppStateManager = new NanoAppStateManager();
100
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700101 /**
102 * Class extending the callback to register with a Context Hub.
103 */
104 private class ContextHubServiceCallback extends IContexthubCallback.Stub {
105 private final int mContextHubId;
106
107 ContextHubServiceCallback(int contextHubId) {
108 mContextHubId = contextHubId;
109 }
110
111 @Override
112 public void handleClientMsg(ContextHubMsg message) {
113 handleClientMessageCallback(mContextHubId, message);
114 }
115
116 @Override
117 public void handleTxnResult(int transactionId, int result) {
118 handleTransactionResultCallback(mContextHubId, transactionId, result);
119 }
120
121 @Override
122 public void handleHubEvent(int eventType) {
123 handleHubEventCallback(mContextHubId, eventType);
124 }
125
126 @Override
127 public void handleAppAbort(long nanoAppId, int abortCode) {
128 handleAppAbortCallback(mContextHubId, nanoAppId, abortCode);
129 }
130
131 @Override
132 public void handleAppsInfo(ArrayList<HubAppInfo> nanoAppInfoList) {
133 handleQueryAppsCallback(mContextHubId, nanoAppInfoList);
134 }
135 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700136
Peng Xu9ff7d222016-02-11 13:02:05 -0800137 public ContextHubService(Context context) {
138 mContext = context;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700139
140 mContextHubProxy = getContextHubProxy();
141 if (mContextHubProxy == null) {
142 mTransactionManager = null;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800143 mClientManager = null;
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800144 mDefaultClientMap = Collections.EMPTY_MAP;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700145 mContextHubInfo = new ContextHubInfo[0];
146 return;
147 }
148
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800149 mClientManager = new ContextHubClientManager(mContext, mContextHubProxy);
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800150 mTransactionManager = new ContextHubTransactionManager(
151 mContextHubProxy, mClientManager, mNanoAppStateManager);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700152
153 List<ContextHub> hubList;
154 try {
155 hubList = mContextHubProxy.getHubs();
156 } catch (RemoteException e) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800157 Log.e(TAG, "RemoteException while getting Context Hub info", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700158 hubList = Collections.emptyList();
159 }
160 mContextHubInfo = ContextHubServiceUtil.createContextHubInfoArray(hubList);
161
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800162 HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
163 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
164 int contextHubId = contextHubInfo.getId();
165
166 IContextHubClient client = mClientManager.registerClient(
167 createDefaultClientCallback(contextHubId), contextHubId);
168 defaultClientMap.put(contextHubId, client);
169 }
170 mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
171
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700172 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
173 int contextHubId = contextHubInfo.getId();
174 try {
175 mContextHubProxy.registerCallback(
176 contextHubId, new ContextHubServiceCallback(contextHubId));
177 } catch (RemoteException e) {
178 Log.e(TAG, "RemoteException while registering service callback for hub (ID = "
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800179 + contextHubId + ")", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700180 }
181 }
182
183 // Do a query to initialize the service cache list of nanoapps
184 // TODO(b/69270990): Remove this when old API is deprecated
185 for (ContextHubInfo contextHubInfo : mContextHubInfo) {
186 queryNanoAppsInternal(contextHubInfo.getId());
187 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800188
189 for (int i = 0; i < mContextHubInfo.length; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700190 Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700191 + ", name: " + mContextHubInfo[i].getName());
Peng Xu9ff7d222016-02-11 13:02:05 -0800192 }
193 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800194
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700195 /**
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800196 * Creates a default client callback for old API clients.
197 *
198 * @param contextHubId the ID of the hub to attach this client to
199 * @return the internal callback interface
200 */
201 private IContextHubClientCallback createDefaultClientCallback(int contextHubId) {
202 return new IContextHubClientCallback.Stub() {
203 @Override
204 public void onMessageFromNanoApp(NanoAppMessage message) {
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800205 int nanoAppHandle = mNanoAppStateManager.getNanoAppHandle(
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800206 contextHubId, message.getNanoAppId());
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800207
208 onMessageReceiptOldApi(
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800209 message.getMessageType(), contextHubId, nanoAppHandle,
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800210 message.getMessageBody());
211 }
212
213 @Override
214 public void onHubReset() {
Arthur Ishiguro6d47c542017-11-17 15:49:07 -0800215 byte[] data = {TransactionResult.SUCCESS};
216 onMessageReceiptOldApi(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800217 }
218
219 @Override
220 public void onNanoAppAborted(long nanoAppId, int abortCode) {
221 }
222
223 @Override
224 public void onNanoAppLoaded(long nanoAppId) {
225 }
226
227 @Override
228 public void onNanoAppUnloaded(long nanoAppId) {
229 }
230
231 @Override
232 public void onNanoAppEnabled(long nanoAppId) {
233 }
234
235 @Override
236 public void onNanoAppDisabled(long nanoAppId) {
237 }
238 };
239 }
240
241 /**
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700242 * @return the IContexthub proxy interface
243 */
244 private IContexthub getContextHubProxy() {
245 IContexthub proxy = null;
246 try {
247 proxy = IContexthub.getService(true /* retry */);
248 } catch (RemoteException e) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800249 Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700250 } catch (NoSuchElementException e) {
251 Log.i(TAG, "Context Hub HAL service not found");
252 }
253
254 return proxy;
255 }
256
Peng Xu9ff7d222016-02-11 13:02:05 -0800257 @Override
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700258 public int registerCallback(IContextHubCallback callback) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700259 checkPermissions();
destradaa78cebca2016-04-14 18:40:14 -0700260 mCallbacksList.register(callback);
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800261
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800262 Log.d(TAG, "Added callback, total callbacks " +
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700263 mCallbacksList.getRegisteredCallbackCount());
Peng Xu9ff7d222016-02-11 13:02:05 -0800264 return 0;
265 }
266
267 @Override
268 public int[] getContextHubHandles() throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700269 checkPermissions();
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700270 int[] returnArray = new int[mContextHubInfo.length];
Peng Xu9ff7d222016-02-11 13:02:05 -0800271
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800272 Log.d(TAG, "System supports " + returnArray.length + " hubs");
Peng Xu9ff7d222016-02-11 13:02:05 -0800273 for (int i = 0; i < returnArray.length; ++i) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700274 returnArray[i] = i;
Peng Xu9ff7d222016-02-11 13:02:05 -0800275 Log.d(TAG, String.format("Hub %s is mapped to %d",
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700276 mContextHubInfo[i].getName(), returnArray[i]));
Peng Xu9ff7d222016-02-11 13:02:05 -0800277 }
278
279 return returnArray;
280 }
281
282 @Override
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700283 public ContextHubInfo getContextHubInfo(int contextHubId) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700284 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700285 if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
286 Log.e(TAG, "Invalid context hub handle " + contextHubId);
Peng Xu9ff7d222016-02-11 13:02:05 -0800287 return null; // null means fail
288 }
289
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700290 return mContextHubInfo[contextHubId];
291 }
292
293 /**
294 * Creates an internal load transaction callback to be used for old API clients
295 *
296 * @param contextHubId the ID of the hub to load the binary
297 * @param nanoAppBinary the binary to load
298 * @return the callback interface
299 */
300 private IContextHubTransactionCallback createLoadTransactionCallback(
301 int contextHubId, NanoAppBinary nanoAppBinary) {
302 return new IContextHubTransactionCallback.Stub() {
303 @Override
304 public void onTransactionComplete(int result) {
305 handleLoadResponseOldApi(contextHubId, result, nanoAppBinary);
306 }
307
308 @Override
309 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
310 }
311 };
312 }
313
314 /**
315 * Creates an internal unload transaction callback to be used for old API clients
316 *
317 * @param contextHubId the ID of the hub to unload the nanoapp
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700318 * @return the callback interface
319 */
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800320 private IContextHubTransactionCallback createUnloadTransactionCallback(int contextHubId) {
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700321 return new IContextHubTransactionCallback.Stub() {
322 @Override
323 public void onTransactionComplete(int result) {
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800324 handleUnloadResponseOldApi(contextHubId, result);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700325 }
326
327 @Override
328 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
329 }
330 };
331 }
332
333 /**
334 * Creates an internal query transaction callback to be used for old API clients
335 *
336 * @param contextHubId the ID of the hub to query
337 * @return the callback interface
338 */
339 private IContextHubTransactionCallback createQueryTransactionCallback(int contextHubId) {
340 return new IContextHubTransactionCallback.Stub() {
341 @Override
342 public void onTransactionComplete(int result) {
343 }
344
345 @Override
346 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
347 byte[] data = {(byte) result};
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800348 onMessageReceiptOldApi(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700349 }
350 };
351 }
352
Peng Xu9ff7d222016-02-11 13:02:05 -0800353 @Override
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700354 public int loadNanoApp(int contextHubId, NanoApp app) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700355 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700356 if (mContextHubProxy == null) {
357 return -1;
358 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800359
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700360 if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
361 Log.e(TAG, "Invalid contextHubhandle " + contextHubId);
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700362 return -1;
Peng Xu9ff7d222016-02-11 13:02:05 -0800363 }
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600364 if (app == null) {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800365 Log.e(TAG, "Invalid null app");
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600366 return -1;
367 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800368
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700369 // Create an internal IContextHubTransactionCallback for the old API clients
370 NanoAppBinary nanoAppBinary = new NanoAppBinary(app.getAppBinary());
371 IContextHubTransactionCallback onCompleteCallback =
372 createLoadTransactionCallback(contextHubId, nanoAppBinary);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700373
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700374 ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
375 contextHubId, nanoAppBinary, onCompleteCallback);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700376
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800377 mTransactionManager.addTransaction(transaction);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700378 return 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800379 }
380
destradaa8bad3fe2016-03-15 12:33:40 -0700381 @Override
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800382 public int unloadNanoApp(int nanoAppHandle) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700383 checkPermissions();
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700384 if (mContextHubProxy == null) {
385 return -1;
386 }
387
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800388 NanoAppInstanceInfo info =
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800389 mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle);
Peng Xu9ff7d222016-02-11 13:02:05 -0800390 if (info == null) {
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800391 Log.e(TAG, "Cannot find nanoapp with handle " + nanoAppHandle);
392 return -1;
Peng Xu9ff7d222016-02-11 13:02:05 -0800393 }
394
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700395 int contextHubId = info.getContexthubId();
396 long nanoAppId = info.getAppId();
397 IContextHubTransactionCallback onCompleteCallback =
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800398 createUnloadTransactionCallback(contextHubId);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700399 ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
400 contextHubId, nanoAppId, onCompleteCallback);
Peng Xu9ff7d222016-02-11 13:02:05 -0800401
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800402 mTransactionManager.addTransaction(transaction);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700403 return 0;
destradaa8bad3fe2016-03-15 12:33:40 -0700404 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800405
406 @Override
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800407 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700408 checkPermissions();
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800409
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800410 return mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle);
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800411 }
412
413 @Override
Peng Xu9ff7d222016-02-11 13:02:05 -0800414 public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700415 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800416
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800417 ArrayList<Integer> foundInstances = new ArrayList<>();
418 for (NanoAppInstanceInfo info : mNanoAppStateManager.getNanoAppInstanceInfoCollection()) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700419 if (filter.testMatch(info)) {
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800420 foundInstances.add(info.getHandle());
Peng Xu9ff7d222016-02-11 13:02:05 -0800421 }
422 }
423
424 int[] retArray = new int[foundInstances.size()];
425 for (int i = 0; i < foundInstances.size(); i++) {
426 retArray[i] = foundInstances.get(i).intValue();
427 }
428
Arthur Ishiguroafe52462017-11-22 15:18:54 -0800429 if (retArray.length == 0) {
430 Log.d(TAG, "No nanoapps found on hub ID " + hubHandle + " using NanoAppFilter: "
431 + filter);
432 }
433
Peng Xu9ff7d222016-02-11 13:02:05 -0800434 return retArray;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800435 }
436
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700437 /**
438 * Performs a query at the specified hub.
439 *
440 * This method should only be invoked internally by the service, either to update the service
441 * cache or as a result of an explicit query requested by a client through the sendMessage API.
442 *
443 * @param contextHubId the ID of the hub to do the query
444 * @return the result of the query
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800445 *
446 * @throws IllegalStateException if the transaction queue is full
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700447 */
448 private int queryNanoAppsInternal(int contextHubId) {
449 if (mContextHubProxy == null) {
450 return Result.UNKNOWN_FAILURE;
451 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700452
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700453 IContextHubTransactionCallback onCompleteCallback =
454 createQueryTransactionCallback(contextHubId);
455 ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
456 contextHubId, onCompleteCallback);
457
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800458 mTransactionManager.addTransaction(transaction);
459 return Result.OK;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700460 }
461
462 @Override
463 public int sendMessage(
464 int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
465 checkPermissions();
466 if (mContextHubProxy == null) {
467 return -1;
468 }
469 if (msg == null) {
470 Log.e(TAG, "ContextHubMessage cannot be null");
471 return -1;
472 }
473 if (msg.getData() == null) {
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800474 Log.e(TAG, "ContextHubMessage message body cannot be null");
475 return -1;
476 }
477 if (!mDefaultClientMap.containsKey(hubHandle)) {
478 Log.e(TAG, "Hub with ID " + hubHandle + " does not exist");
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600479 return -1;
480 }
481
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800482 boolean success = false;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700483 if (nanoAppHandle == OS_APP_INSTANCE) {
484 if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800485 success = (queryNanoAppsInternal(hubHandle) == Result.OK);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700486 } else {
487 Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType());
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700488 }
489 } else {
490 NanoAppInstanceInfo info = getNanoAppInstanceInfo(nanoAppHandle);
491 if (info != null) {
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800492 NanoAppMessage message = NanoAppMessage.createMessageToNanoApp(
493 info.getAppId(), msg.getMsgType(), msg.getData());
Peng Xu9ff7d222016-02-11 13:02:05 -0800494
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800495 IContextHubClient client = mDefaultClientMap.get(hubHandle);
496 success = (client.sendMessageToNanoApp(message) ==
497 ContextHubTransaction.TRANSACTION_SUCCESS);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700498 } else {
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800499 Log.e(TAG, "Failed to send nanoapp message - nanoapp with handle "
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700500 + nanoAppHandle + " does not exist.");
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700501 }
502 }
503
Arthur Ishiguroebb0e862017-11-17 14:55:32 -0800504 return success ? 0 : -1;
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700505 }
506
507 /**
508 * Handles a unicast or broadcast message from a nanoapp.
509 *
510 * @param contextHubId the ID of the hub the message came from
511 * @param message the message contents
512 */
513 private void handleClientMessageCallback(int contextHubId, ContextHubMsg message) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800514 mClientManager.onMessageFromNanoApp(contextHubId, message);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700515 }
516
517 /**
518 * A helper function to handle a load response from the Context Hub for the old API.
519 *
520 * TODO(b/69270990): Remove this once the old APIs are obsolete.
521 */
522 private void handleLoadResponseOldApi(
523 int contextHubId, int result, NanoAppBinary nanoAppBinary) {
524 if (nanoAppBinary == null) {
525 Log.e(TAG, "Nanoapp binary field was null for a load transaction");
526 return;
527 }
528
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700529 byte[] data = new byte[5];
530 data[0] = (byte) result;
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800531 int nanoAppHandle = mNanoAppStateManager.getNanoAppHandle(
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800532 contextHubId, nanoAppBinary.getNanoAppId());
Arthur Ishiguro2fc5a4b2017-12-11 15:15:44 -0800533 ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(nanoAppHandle);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700534
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800535 onMessageReceiptOldApi(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700536 }
537
538 /**
539 * A helper function to handle an unload response from the Context Hub for the old API.
540 *
541 * TODO(b/69270990): Remove this once the old APIs are obsolete.
542 */
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800543 private void handleUnloadResponseOldApi(int contextHubId, int result) {
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700544 byte[] data = new byte[1];
545 data[0] = (byte) result;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800546 onMessageReceiptOldApi(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700547 }
548
549 /**
550 * Handles a transaction response from a Context Hub.
551 *
552 * @param contextHubId the ID of the hub the response came from
553 * @param transactionId the ID of the transaction
554 * @param result the result of the transaction reported by the hub
555 */
556 private void handleTransactionResultCallback(int contextHubId, int transactionId, int result) {
557 mTransactionManager.onTransactionResponse(transactionId, result);
558 }
559
560 /**
561 * Handles an asynchronous event from a Context Hub.
562 *
563 * @param contextHubId the ID of the hub the response came from
564 * @param eventType the type of the event as defined in Context Hub HAL AsyncEventType
565 */
566 private void handleHubEventCallback(int contextHubId, int eventType) {
567 if (eventType == AsyncEventType.RESTARTED) {
568 mTransactionManager.onHubReset();
569 queryNanoAppsInternal(contextHubId);
570
Arthur Ishiguro6d47c542017-11-17 15:49:07 -0800571 mClientManager.onHubReset(contextHubId);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700572 } else {
573 Log.i(TAG, "Received unknown hub event (hub ID = " + contextHubId + ", type = "
574 + eventType + ")");
575 }
576 }
577
578 /**
579 * Handles an asynchronous abort event of a nanoapp.
580 *
581 * @param contextHubId the ID of the hub that the nanoapp aborted in
582 * @param nanoAppId the ID of the aborted nanoapp
583 * @param abortCode the nanoapp-specific abort code
584 */
585 private void handleAppAbortCallback(int contextHubId, long nanoAppId, int abortCode) {
586 // TODO(b/31049861): Implement this
587 }
588
589 /**
590 * Handles a query response from a Context Hub.
591 *
592 * @param contextHubId the ID of the hub of the response
593 * @param nanoAppInfoList the list of loaded nanoapps
594 */
595 private void handleQueryAppsCallback(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
596 List<NanoAppState> nanoAppStateList =
597 ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
598
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800599 mNanoAppStateManager.updateCache(contextHubId, nanoAppInfoList);
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700600 mTransactionManager.onQueryResponse(nanoAppStateList);
601 }
602
603 /**
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800604 * @param contextHubId the hub ID to validate
605 * @return {@code true} if the ID represents that of an available hub, {@code false} otherwise
606 */
607 private boolean isValidContextHubId(int contextHubId) {
608 for (ContextHubInfo hubInfo : mContextHubInfo) {
609 if (hubInfo.getId() == contextHubId) {
610 return true;
611 }
612 }
613
614 return false;
615 }
616
617 /**
618 * Creates and registers a client at the service for the specified Context Hub.
619 *
620 * @param clientCallback the client interface to register with the service
621 * @param contextHubId the ID of the hub this client is attached to
622 * @return the generated client interface, null if registration was unsuccessful
623 *
624 * @throws IllegalArgumentException if contextHubId is not a valid ID
625 * @throws IllegalStateException if max number of clients have already registered
626 * @throws NullPointerException if clientCallback is null
627 */
628 @Override
629 public IContextHubClient createClient(
630 IContextHubClientCallback clientCallback, int contextHubId) throws RemoteException {
631 checkPermissions();
632 if (!isValidContextHubId(contextHubId)) {
633 throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
634 }
635 if (clientCallback == null) {
636 throw new NullPointerException("Cannot register client with null callback");
637 }
638
639 return mClientManager.registerClient(clientCallback, contextHubId);
640 }
641
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800642 /**
643 * Loads a nanoapp binary at the specified Context hub.
644 *
645 * @param contextHubId the ID of the hub to load the binary
646 * @param transactionCallback the client-facing transaction callback interface
647 * @param nanoAppBinary the binary to load
648 *
649 * @throws RemoteException
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800650 * @throws IllegalStateException if the transaction queue is full
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800651 */
652 @Override
653 public void loadNanoAppOnHub(
654 int contextHubId, IContextHubTransactionCallback transactionCallback,
655 NanoAppBinary nanoAppBinary) throws RemoteException {
656 checkPermissions();
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800657 if (!checkHalProxyAndContextHubId(
658 contextHubId, transactionCallback, ContextHubTransaction.TYPE_LOAD_NANOAPP)) {
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800659 return;
660 }
661 if (nanoAppBinary == null) {
662 Log.e(TAG, "NanoAppBinary cannot be null in loadNanoAppOnHub");
663 transactionCallback.onTransactionComplete(
664 ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
665 return;
666 }
667
668 ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
669 contextHubId, nanoAppBinary, transactionCallback);
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800670 mTransactionManager.addTransaction(transaction);
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800671 }
672
673 /**
674 * Unloads a nanoapp from the specified Context Hub.
675 *
676 * @param contextHubId the ID of the hub to unload the nanoapp
677 * @param transactionCallback the client-facing transaction callback interface
678 * @param nanoAppId the ID of the nanoapp to unload
679 *
680 * @throws RemoteException
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800681 * @throws IllegalStateException if the transaction queue is full
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800682 */
683 @Override
684 public void unloadNanoAppFromHub(
685 int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId)
686 throws RemoteException {
687 checkPermissions();
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800688 if (!checkHalProxyAndContextHubId(
689 contextHubId, transactionCallback, ContextHubTransaction.TYPE_UNLOAD_NANOAPP)) {
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800690 return;
691 }
692
693 ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
694 contextHubId, nanoAppId, transactionCallback);
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800695 mTransactionManager.addTransaction(transaction);
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800696 }
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800697
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800698 /**
699 * Queries for a list of nanoapps from the specified Context hub.
700 *
701 * @param contextHubId the ID of the hub to query
702 * @param transactionCallback the client-facing transaction callback interface
703 *
704 * @throws RemoteException
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800705 * @throws IllegalStateException if the transaction queue is full
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800706 */
707 @Override
708 public void queryNanoApps(int contextHubId, IContextHubTransactionCallback transactionCallback)
709 throws RemoteException {
710 checkPermissions();
711 if (!checkHalProxyAndContextHubId(
712 contextHubId, transactionCallback, ContextHubTransaction.TYPE_QUERY_NANOAPPS)) {
713 return;
714 }
715
716 ContextHubServiceTransaction transaction =
717 mTransactionManager.createQueryTransaction(contextHubId, transactionCallback);
Arthur Ishiguroe60f91a2017-11-30 09:48:00 -0800718 mTransactionManager.addTransaction(transaction);
Arthur Ishiguroe1ade432017-11-27 10:45:33 -0800719 }
720
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700721 @Override
722 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600723 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700724
725 pw.println("Dumping ContextHub Service");
726
727 pw.println("");
728 // dump ContextHubInfo
729 pw.println("=================== CONTEXT HUBS ====================");
730 for (int i = 0; i < mContextHubInfo.length; i++) {
731 pw.println("Handle " + i + " : " + mContextHubInfo[i].toString());
732 }
733 pw.println("");
734 pw.println("=================== NANOAPPS ====================");
735 // Dump nanoAppHash
Arthur Ishigurofb9e4c72017-11-21 15:33:21 -0800736 for (NanoAppInstanceInfo info : mNanoAppStateManager.getNanoAppInstanceInfoCollection()) {
737 pw.println(info);
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700738 }
739
740 // dump eventLog
741 }
742
destradaa8bad3fe2016-03-15 12:33:40 -0700743 private void checkPermissions() {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800744 ContextHubServiceUtil.checkPermissions(mContext);
destradaa8bad3fe2016-03-15 12:33:40 -0700745 }
Ashutosh Joshi2c697fb2016-04-01 20:48:13 +0000746
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800747 private int onMessageReceiptOldApi(int msgType, int hubHandle, int appInstance, byte[] data) {
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700748 if (data == null) {
749 return -1;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700750 }
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800751
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700752 int msgVersion = 0;
destradaa78cebca2016-04-14 18:40:14 -0700753 int callbacksCount = mCallbacksList.beginBroadcast();
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800754 Log.d(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle " +
Arthur Ishiguro7a23a962017-11-01 10:52:28 -0700755 hubHandle + ", appInstance " + appInstance + ", callBackCount " + callbacksCount);
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800756
destradaa78cebca2016-04-14 18:40:14 -0700757 if (callbacksCount < 1) {
758 Log.v(TAG, "No message callbacks registered.");
759 return 0;
760 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700761
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800762 ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
destradaa78cebca2016-04-14 18:40:14 -0700763 for (int i = 0; i < callbacksCount; ++i) {
764 IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
765 try {
Ashutosh Joshi1d941812017-03-09 15:21:24 -0800766 callback.onMessageReceipt(hubHandle, appInstance, msg);
destradaa78cebca2016-04-14 18:40:14 -0700767 } catch (RemoteException e) {
768 Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
769 continue;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700770 }
771 }
destradaa78cebca2016-04-14 18:40:14 -0700772 mCallbacksList.finishBroadcast();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700773 return 0;
774 }
775
Arthur Ishiguro4493e142017-11-27 16:26:34 -0800776 /**
777 * Validates the HAL proxy state and context hub ID to see if we can start the transaction.
778 *
779 * @param contextHubId the ID of the hub to start the transaction
780 * @param callback the client transaction callback interface
781 * @param transactionType the type of the transaction
782 *
783 * @return {@code true} if mContextHubProxy and contextHubId is valid, {@code false} otherwise
784 */
785 private boolean checkHalProxyAndContextHubId(
786 int contextHubId, IContextHubTransactionCallback callback,
787 @ContextHubTransaction.Type int transactionType) {
788 if (mContextHubProxy == null) {
789 try {
790 callback.onTransactionComplete(
791 ContextHubTransaction.TRANSACTION_FAILED_HAL_UNAVAILABLE);
792 } catch (RemoteException e) {
793 Log.e(TAG, "RemoteException while calling onTransactionComplete", e);
794 }
795 return false;
796 }
797 if (!isValidContextHubId(contextHubId)) {
798 Log.e(TAG, "Cannot start "
799 + ContextHubTransaction.typeToString(transactionType, false /* upperCase */)
800 + " transaction for invalid hub ID " + contextHubId);
801 try {
802 callback.onTransactionComplete(ContextHubTransaction.TRANSACTION_FAILED_BAD_PARAMS);
803 } catch (RemoteException e) {
804 Log.e(TAG, "RemoteException while calling onTransactionComplete", e);
805 }
806 return false;
807 }
808
809 return true;
810 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700811}