1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location; 18 19 import android.content.Context; 20 import android.hardware.contexthub.V1_0.AsyncEventType; 21 import android.hardware.contexthub.V1_0.ContextHub; 22 import android.hardware.contexthub.V1_0.ContextHubMsg; 23 import android.hardware.contexthub.V1_0.HubAppInfo; 24 import android.hardware.contexthub.V1_0.IContexthub; 25 import android.hardware.contexthub.V1_0.IContexthubCallback; 26 import android.hardware.contexthub.V1_0.Result; 27 import android.hardware.contexthub.V1_0.TransactionResult; 28 import android.hardware.location.ContextHubInfo; 29 import android.hardware.location.ContextHubMessage; 30 import android.hardware.location.ContextHubTransaction; 31 import android.hardware.location.IContextHubCallback; 32 import android.hardware.location.IContextHubClient; 33 import android.hardware.location.IContextHubClientCallback; 34 import android.hardware.location.IContextHubService; 35 import android.hardware.location.IContextHubTransactionCallback; 36 import android.hardware.location.NanoApp; 37 import android.hardware.location.NanoAppBinary; 38 import android.hardware.location.NanoAppFilter; 39 import android.hardware.location.NanoAppInstanceInfo; 40 import android.hardware.location.NanoAppMessage; 41 import android.hardware.location.NanoAppState; 42 import android.os.RemoteCallbackList; 43 import android.os.RemoteException; 44 import android.util.Log; 45 46 import com.android.internal.util.DumpUtils; 47 48 import java.io.FileDescriptor; 49 import java.io.PrintWriter; 50 import java.nio.ByteBuffer; 51 import java.nio.ByteOrder; 52 import java.util.ArrayList; 53 import java.util.Collections; 54 import java.util.HashMap; 55 import java.util.List; 56 import java.util.Map; 57 import java.util.NoSuchElementException; 58 59 /** 60 * @hide 61 */ 62 public class ContextHubService extends IContextHubService.Stub { 63 private static final String TAG = "ContextHubService"; 64 65 /* 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; 73 public static final int MSG_UNLOAD_NANO_APP = 4; 74 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; 77 78 private static final int OS_APP_INSTANCE = -1; 79 80 private final Context mContext; 81 82 private final Map<Integer, ContextHubInfo> mContextHubIdToInfoMap; 83 private final List<ContextHubInfo> mContextHubInfoList; 84 private final RemoteCallbackList<IContextHubCallback> mCallbacksList = 85 new RemoteCallbackList<>(); 86 87 // Proxy object to communicate with the Context Hub HAL 88 private final IContexthub mContextHubProxy; 89 90 // The manager for transaction queue 91 private final ContextHubTransactionManager mTransactionManager; 92 93 // The manager for sending messages to/from clients 94 private final ContextHubClientManager mClientManager; 95 96 // The default client for old API clients 97 private final Map<Integer, IContextHubClient> mDefaultClientMap; 98 99 // The manager for the internal nanoapp state cache 100 private final NanoAppStateManager mNanoAppStateManager = new NanoAppStateManager(); 101 102 /** 103 * Class extending the callback to register with a Context Hub. 104 */ 105 private class ContextHubServiceCallback extends IContexthubCallback.Stub { 106 private final int mContextHubId; 107 108 ContextHubServiceCallback(int contextHubId) { 109 mContextHubId = contextHubId; 110 } 111 112 @Override 113 public void handleClientMsg(ContextHubMsg message) { 114 handleClientMessageCallback(mContextHubId, message); 115 } 116 117 @Override 118 public void handleTxnResult(int transactionId, int result) { 119 handleTransactionResultCallback(mContextHubId, transactionId, result); 120 } 121 122 @Override 123 public void handleHubEvent(int eventType) { 124 handleHubEventCallback(mContextHubId, eventType); 125 } 126 127 @Override 128 public void handleAppAbort(long nanoAppId, int abortCode) { 129 handleAppAbortCallback(mContextHubId, nanoAppId, abortCode); 130 } 131 132 @Override 133 public void handleAppsInfo(ArrayList<HubAppInfo> nanoAppInfoList) { 134 handleQueryAppsCallback(mContextHubId, nanoAppInfoList); 135 } 136 } 137 138 public ContextHubService(Context context) { 139 mContext = context; 140 141 mContextHubProxy = getContextHubProxy(); 142 if (mContextHubProxy == null) { 143 mTransactionManager = null; 144 mClientManager = null; 145 mDefaultClientMap = Collections.emptyMap(); 146 mContextHubIdToInfoMap = Collections.emptyMap(); 147 mContextHubInfoList = Collections.emptyList(); 148 return; 149 } 150 151 mClientManager = new ContextHubClientManager(mContext, mContextHubProxy); 152 mTransactionManager = new ContextHubTransactionManager( 153 mContextHubProxy, mClientManager, mNanoAppStateManager); 154 155 List<ContextHub> hubList; 156 try { 157 hubList = mContextHubProxy.getHubs(); 158 } catch (RemoteException e) { 159 Log.e(TAG, "RemoteException while getting Context Hub info", e); 160 hubList = Collections.emptyList(); 161 } 162 mContextHubIdToInfoMap = Collections.unmodifiableMap( 163 ContextHubServiceUtil.createContextHubInfoMap(hubList)); 164 mContextHubInfoList = new ArrayList<>(mContextHubIdToInfoMap.values()); 165 166 HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>(); 167 for (int contextHubId : mContextHubIdToInfoMap.keySet()) { 168 IContextHubClient client = mClientManager.registerClient( 169 createDefaultClientCallback(contextHubId), contextHubId); 170 defaultClientMap.put(contextHubId, client); 171 172 try { 173 mContextHubProxy.registerCallback( 174 contextHubId, new ContextHubServiceCallback(contextHubId)); 175 } catch (RemoteException e) { 176 Log.e(TAG, "RemoteException while registering service callback for hub (ID = " 177 + contextHubId + ")", e); 178 } 179 180 // Do a query to initialize the service cache list of nanoapps 181 // TODO(b/69270990): Remove this when old API is deprecated 182 queryNanoAppsInternal(contextHubId); 183 } 184 mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap); 185 } 186 187 /** 188 * Creates a default client callback for old API clients. 189 * 190 * @param contextHubId the ID of the hub to attach this client to 191 * @return the internal callback interface 192 */ 193 private IContextHubClientCallback createDefaultClientCallback(int contextHubId) { 194 return new IContextHubClientCallback.Stub() { 195 @Override 196 public void onMessageFromNanoApp(NanoAppMessage message) { 197 int nanoAppHandle = mNanoAppStateManager.getNanoAppHandle( 198 contextHubId, message.getNanoAppId()); 199 200 onMessageReceiptOldApi( 201 message.getMessageType(), contextHubId, nanoAppHandle, 202 message.getMessageBody()); 203 } 204 205 @Override 206 public void onHubReset() { 207 byte[] data = {TransactionResult.SUCCESS}; 208 onMessageReceiptOldApi(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data); 209 } 210 211 @Override 212 public void onNanoAppAborted(long nanoAppId, int abortCode) { 213 } 214 215 @Override 216 public void onNanoAppLoaded(long nanoAppId) { 217 } 218 219 @Override 220 public void onNanoAppUnloaded(long nanoAppId) { 221 } 222 223 @Override 224 public void onNanoAppEnabled(long nanoAppId) { 225 } 226 227 @Override 228 public void onNanoAppDisabled(long nanoAppId) { 229 } 230 }; 231 } 232 233 /** 234 * @return the IContexthub proxy interface 235 */ 236 private IContexthub getContextHubProxy() { 237 IContexthub proxy = null; 238 try { 239 proxy = IContexthub.getService(true /* retry */); 240 } catch (RemoteException e) { 241 Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e); 242 } catch (NoSuchElementException e) { 243 Log.i(TAG, "Context Hub HAL service not found"); 244 } 245 246 return proxy; 247 } 248 249 @Override 250 public int registerCallback(IContextHubCallback callback) throws RemoteException { 251 checkPermissions(); 252 mCallbacksList.register(callback); 253 254 Log.d(TAG, "Added callback, total callbacks " + 255 mCallbacksList.getRegisteredCallbackCount()); 256 return 0; 257 } 258 259 @Override 260 public int[] getContextHubHandles() throws RemoteException { 261 checkPermissions(); 262 return ContextHubServiceUtil.createPrimitiveIntArray(mContextHubIdToInfoMap.keySet()); 263 } 264 265 @Override 266 public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException { 267 checkPermissions(); 268 if (!mContextHubIdToInfoMap.containsKey(contextHubHandle)) { 269 Log.e(TAG, "Invalid Context Hub handle " + contextHubHandle + " in getContextHubInfo"); 270 return null; 271 } 272 273 return mContextHubIdToInfoMap.get(contextHubHandle); 274 } 275 276 /** 277 * Returns a List of ContextHubInfo object describing the available hubs. 278 * 279 * @return the List of ContextHubInfo objects 280 */ 281 @Override 282 public List<ContextHubInfo> getContextHubs() throws RemoteException { 283 checkPermissions(); 284 return mContextHubInfoList; 285 } 286 287 /** 288 * Creates an internal load transaction callback to be used for old API clients 289 * 290 * @param contextHubId the ID of the hub to load the binary 291 * @param nanoAppBinary the binary to load 292 * @return the callback interface 293 */ 294 private IContextHubTransactionCallback createLoadTransactionCallback( 295 int contextHubId, NanoAppBinary nanoAppBinary) { 296 return new IContextHubTransactionCallback.Stub() { 297 @Override 298 public void onTransactionComplete(int result) { 299 handleLoadResponseOldApi(contextHubId, result, nanoAppBinary); 300 } 301 302 @Override 303 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) { 304 } 305 }; 306 } 307 308 /** 309 * Creates an internal unload transaction callback to be used for old API clients 310 * 311 * @param contextHubId the ID of the hub to unload the nanoapp 312 * @return the callback interface 313 */ 314 private IContextHubTransactionCallback createUnloadTransactionCallback(int contextHubId) { 315 return new IContextHubTransactionCallback.Stub() { 316 @Override 317 public void onTransactionComplete(int result) { 318 handleUnloadResponseOldApi(contextHubId, result); 319 } 320 321 @Override 322 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) { 323 } 324 }; 325 } 326 327 /** 328 * Creates an internal query transaction callback to be used for old API clients 329 * 330 * @param contextHubId the ID of the hub to query 331 * @return the callback interface 332 */ 333 private IContextHubTransactionCallback createQueryTransactionCallback(int contextHubId) { 334 return new IContextHubTransactionCallback.Stub() { 335 @Override 336 public void onTransactionComplete(int result) { 337 } 338 339 @Override 340 public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) { 341 byte[] data = {(byte) result}; 342 onMessageReceiptOldApi(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data); 343 } 344 }; 345 } 346 347 @Override 348 public int loadNanoApp(int contextHubHandle, NanoApp nanoApp) throws RemoteException { 349 checkPermissions(); 350 if (mContextHubProxy == null) { 351 return -1; 352 } 353 if (!isValidContextHubId(contextHubHandle)) { 354 Log.e(TAG, "Invalid Context Hub handle " + contextHubHandle + " in loadNanoApp"); 355 return -1; 356 } 357 if (nanoApp == null) { 358 Log.e(TAG, "NanoApp cannot be null in loadNanoApp"); 359 return -1; 360 } 361 362 // Create an internal IContextHubTransactionCallback for the old API clients 363 NanoAppBinary nanoAppBinary = new NanoAppBinary(nanoApp.getAppBinary()); 364 IContextHubTransactionCallback onCompleteCallback = 365 createLoadTransactionCallback(contextHubHandle, nanoAppBinary); 366 367 ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction( 368 contextHubHandle, nanoAppBinary, onCompleteCallback); 369 370 mTransactionManager.addTransaction(transaction); 371 return 0; 372 } 373 374 @Override 375 public int unloadNanoApp(int nanoAppHandle) throws RemoteException { 376 checkPermissions(); 377 if (mContextHubProxy == null) { 378 return -1; 379 } 380 381 NanoAppInstanceInfo info = 382 mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle); 383 if (info == null) { 384 Log.e(TAG, "Invalid nanoapp handle " + nanoAppHandle + " in unloadNanoApp"); 385 return -1; 386 } 387 388 int contextHubId = info.getContexthubId(); 389 long nanoAppId = info.getAppId(); 390 IContextHubTransactionCallback onCompleteCallback = 391 createUnloadTransactionCallback(contextHubId); 392 ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction( 393 contextHubId, nanoAppId, onCompleteCallback); 394 395 mTransactionManager.addTransaction(transaction); 396 return 0; 397 } 398 399 @Override 400 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) throws RemoteException { 401 checkPermissions(); 402 403 return mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle); 404 } 405 406 @Override 407 public int[] findNanoAppOnHub( 408 int contextHubHandle, NanoAppFilter filter) throws RemoteException { 409 checkPermissions(); 410 411 ArrayList<Integer> foundInstances = new ArrayList<>(); 412 for (NanoAppInstanceInfo info : mNanoAppStateManager.getNanoAppInstanceInfoCollection()) { 413 if (filter.testMatch(info)) { 414 foundInstances.add(info.getHandle()); 415 } 416 } 417 418 int[] retArray = new int[foundInstances.size()]; 419 for (int i = 0; i < foundInstances.size(); i++) { 420 retArray[i] = foundInstances.get(i).intValue(); 421 } 422 return retArray; 423 } 424 425 /** 426 * Performs a query at the specified hub. 427 * 428 * This method should only be invoked internally by the service, either to update the service 429 * cache or as a result of an explicit query requested by a client through the sendMessage API. 430 * 431 * @param contextHubId the ID of the hub to do the query 432 * @return the result of the query 433 * 434 * @throws IllegalStateException if the transaction queue is full 435 */ 436 private int queryNanoAppsInternal(int contextHubId) { 437 if (mContextHubProxy == null) { 438 return Result.UNKNOWN_FAILURE; 439 } 440 441 IContextHubTransactionCallback onCompleteCallback = 442 createQueryTransactionCallback(contextHubId); 443 ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( 444 contextHubId, onCompleteCallback); 445 446 mTransactionManager.addTransaction(transaction); 447 return Result.OK; 448 } 449 450 @Override 451 public int sendMessage(int contextHubHandle, int nanoAppHandle, ContextHubMessage msg) 452 throws RemoteException { 453 checkPermissions(); 454 if (mContextHubProxy == null) { 455 return -1; 456 } 457 if (msg == null) { 458 Log.e(TAG, "ContextHubMessage cannot be null in sendMessage"); 459 return -1; 460 } 461 if (msg.getData() == null) { 462 Log.e(TAG, "ContextHubMessage message body cannot be null in sendMessage"); 463 return -1; 464 } 465 if (!isValidContextHubId(contextHubHandle)) { 466 Log.e(TAG, "Invalid Context Hub handle " + contextHubHandle + " in sendMessage"); 467 return -1; 468 } 469 470 boolean success = false; 471 if (nanoAppHandle == OS_APP_INSTANCE) { 472 if (msg.getMsgType() == MSG_QUERY_NANO_APPS) { 473 success = (queryNanoAppsInternal(contextHubHandle) == Result.OK); 474 } else { 475 Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType()); 476 } 477 } else { 478 NanoAppInstanceInfo info = getNanoAppInstanceInfo(nanoAppHandle); 479 if (info != null) { 480 NanoAppMessage message = NanoAppMessage.createMessageToNanoApp( 481 info.getAppId(), msg.getMsgType(), msg.getData()); 482 483 IContextHubClient client = mDefaultClientMap.get(contextHubHandle); 484 success = (client.sendMessageToNanoApp(message) == 485 ContextHubTransaction.RESULT_SUCCESS); 486 } else { 487 Log.e(TAG, "Failed to send nanoapp message - nanoapp with handle " 488 + nanoAppHandle + " does not exist."); 489 } 490 } 491 492 return success ? 0 : -1; 493 } 494 495 /** 496 * Handles a unicast or broadcast message from a nanoapp. 497 * 498 * @param contextHubId the ID of the hub the message came from 499 * @param message the message contents 500 */ 501 private void handleClientMessageCallback(int contextHubId, ContextHubMsg message) { 502 mClientManager.onMessageFromNanoApp(contextHubId, message); 503 } 504 505 /** 506 * A helper function to handle a load response from the Context Hub for the old API. 507 * 508 * TODO(b/69270990): Remove this once the old APIs are obsolete. 509 */ 510 private void handleLoadResponseOldApi( 511 int contextHubId, int result, NanoAppBinary nanoAppBinary) { 512 if (nanoAppBinary == null) { 513 Log.e(TAG, "Nanoapp binary field was null for a load transaction"); 514 return; 515 } 516 517 byte[] data = new byte[5]; 518 data[0] = (byte) result; 519 int nanoAppHandle = mNanoAppStateManager.getNanoAppHandle( 520 contextHubId, nanoAppBinary.getNanoAppId()); 521 ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(nanoAppHandle); 522 523 onMessageReceiptOldApi(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data); 524 } 525 526 /** 527 * A helper function to handle an unload response from the Context Hub for the old API. 528 * 529 * TODO(b/69270990): Remove this once the old APIs are obsolete. 530 */ 531 private void handleUnloadResponseOldApi(int contextHubId, int result) { 532 byte[] data = new byte[1]; 533 data[0] = (byte) result; 534 onMessageReceiptOldApi(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data); 535 } 536 537 /** 538 * Handles a transaction response from a Context Hub. 539 * 540 * @param contextHubId the ID of the hub the response came from 541 * @param transactionId the ID of the transaction 542 * @param result the result of the transaction reported by the hub 543 */ 544 private void handleTransactionResultCallback(int contextHubId, int transactionId, int result) { 545 mTransactionManager.onTransactionResponse(transactionId, result); 546 } 547 548 /** 549 * Handles an asynchronous event from a Context Hub. 550 * 551 * @param contextHubId the ID of the hub the response came from 552 * @param eventType the type of the event as defined in Context Hub HAL AsyncEventType 553 */ 554 private void handleHubEventCallback(int contextHubId, int eventType) { 555 if (eventType == AsyncEventType.RESTARTED) { 556 mTransactionManager.onHubReset(); 557 queryNanoAppsInternal(contextHubId); 558 559 mClientManager.onHubReset(contextHubId); 560 } else { 561 Log.i(TAG, "Received unknown hub event (hub ID = " + contextHubId + ", type = " 562 + eventType + ")"); 563 } 564 } 565 566 /** 567 * Handles an asynchronous abort event of a nanoapp. 568 * 569 * @param contextHubId the ID of the hub that the nanoapp aborted in 570 * @param nanoAppId the ID of the aborted nanoapp 571 * @param abortCode the nanoapp-specific abort code 572 */ 573 private void handleAppAbortCallback(int contextHubId, long nanoAppId, int abortCode) { 574 mClientManager.onNanoAppAborted(contextHubId, nanoAppId, abortCode); 575 } 576 577 /** 578 * Handles a query response from a Context Hub. 579 * 580 * @param contextHubId the ID of the hub of the response 581 * @param nanoAppInfoList the list of loaded nanoapps 582 */ 583 private void handleQueryAppsCallback(int contextHubId, List<HubAppInfo> nanoAppInfoList) { 584 List<NanoAppState> nanoAppStateList = 585 ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList); 586 587 mNanoAppStateManager.updateCache(contextHubId, nanoAppInfoList); 588 mTransactionManager.onQueryResponse(nanoAppStateList); 589 } 590 591 /** 592 * @param contextHubId the hub ID to validate 593 * @return {@code true} if the ID represents that of an available hub, {@code false} otherwise 594 */ 595 private boolean isValidContextHubId(int contextHubId) { 596 return mContextHubIdToInfoMap.containsKey(contextHubId); 597 } 598 599 /** 600 * Creates and registers a client at the service for the specified Context Hub. 601 * 602 * @param clientCallback the client interface to register with the service 603 * @param contextHubId the ID of the hub this client is attached to 604 * @return the generated client interface, null if registration was unsuccessful 605 * 606 * @throws IllegalArgumentException if contextHubId is not a valid ID 607 * @throws IllegalStateException if max number of clients have already registered 608 * @throws NullPointerException if clientCallback is null 609 */ 610 @Override 611 public IContextHubClient createClient( 612 IContextHubClientCallback clientCallback, int contextHubId) throws RemoteException { 613 checkPermissions(); 614 if (!isValidContextHubId(contextHubId)) { 615 throw new IllegalArgumentException("Invalid context hub ID " + contextHubId); 616 } 617 if (clientCallback == null) { 618 throw new NullPointerException("Cannot register client with null callback"); 619 } 620 621 return mClientManager.registerClient(clientCallback, contextHubId); 622 } 623 624 /** 625 * Loads a nanoapp binary at the specified Context hub. 626 * 627 * @param contextHubId the ID of the hub to load the binary 628 * @param transactionCallback the client-facing transaction callback interface 629 * @param nanoAppBinary the binary to load 630 * 631 * @throws IllegalStateException if the transaction queue is full 632 */ 633 @Override 634 public void loadNanoAppOnHub( 635 int contextHubId, IContextHubTransactionCallback transactionCallback, 636 NanoAppBinary nanoAppBinary) throws RemoteException { 637 checkPermissions(); 638 if (!checkHalProxyAndContextHubId( 639 contextHubId, transactionCallback, ContextHubTransaction.TYPE_LOAD_NANOAPP)) { 640 return; 641 } 642 if (nanoAppBinary == null) { 643 Log.e(TAG, "NanoAppBinary cannot be null in loadNanoAppOnHub"); 644 transactionCallback.onTransactionComplete( 645 ContextHubTransaction.RESULT_FAILED_BAD_PARAMS); 646 return; 647 } 648 649 ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction( 650 contextHubId, nanoAppBinary, transactionCallback); 651 mTransactionManager.addTransaction(transaction); 652 } 653 654 /** 655 * Unloads a nanoapp from the specified Context Hub. 656 * 657 * @param contextHubId the ID of the hub to unload the nanoapp 658 * @param transactionCallback the client-facing transaction callback interface 659 * @param nanoAppId the ID of the nanoapp to unload 660 * 661 * @throws IllegalStateException if the transaction queue is full 662 */ 663 @Override 664 public void unloadNanoAppFromHub( 665 int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId) 666 throws RemoteException { 667 checkPermissions(); 668 if (!checkHalProxyAndContextHubId( 669 contextHubId, transactionCallback, ContextHubTransaction.TYPE_UNLOAD_NANOAPP)) { 670 return; 671 } 672 673 ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction( 674 contextHubId, nanoAppId, transactionCallback); 675 mTransactionManager.addTransaction(transaction); 676 } 677 678 /** 679 * Enables a nanoapp at the specified Context Hub. 680 * 681 * @param contextHubId the ID of the hub to enable the nanoapp 682 * @param transactionCallback the client-facing transaction callback interface 683 * @param nanoAppId the ID of the nanoapp to enable 684 * 685 * @throws IllegalStateException if the transaction queue is full 686 */ 687 @Override 688 public void enableNanoApp( 689 int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId) 690 throws RemoteException { 691 checkPermissions(); 692 if (!checkHalProxyAndContextHubId( 693 contextHubId, transactionCallback, ContextHubTransaction.TYPE_ENABLE_NANOAPP)) { 694 return; 695 } 696 697 ContextHubServiceTransaction transaction = mTransactionManager.createEnableTransaction( 698 contextHubId, nanoAppId, transactionCallback); 699 mTransactionManager.addTransaction(transaction); 700 } 701 702 /** 703 * Disables a nanoapp at the specified Context Hub. 704 * 705 * @param contextHubId the ID of the hub to disable the nanoapp 706 * @param transactionCallback the client-facing transaction callback interface 707 * @param nanoAppId the ID of the nanoapp to disable 708 * 709 * @throws IllegalStateException if the transaction queue is full 710 */ 711 @Override 712 public void disableNanoApp( 713 int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId) 714 throws RemoteException { 715 checkPermissions(); 716 if (!checkHalProxyAndContextHubId( 717 contextHubId, transactionCallback, ContextHubTransaction.TYPE_DISABLE_NANOAPP)) { 718 return; 719 } 720 721 ContextHubServiceTransaction transaction = mTransactionManager.createDisableTransaction( 722 contextHubId, nanoAppId, transactionCallback); 723 mTransactionManager.addTransaction(transaction); 724 } 725 726 /** 727 * Queries for a list of nanoapps from the specified Context hub. 728 * 729 * @param contextHubId the ID of the hub to query 730 * @param transactionCallback the client-facing transaction callback interface 731 * 732 * @throws IllegalStateException if the transaction queue is full 733 */ 734 @Override 735 public void queryNanoApps(int contextHubId, IContextHubTransactionCallback transactionCallback) 736 throws RemoteException { 737 checkPermissions(); 738 if (!checkHalProxyAndContextHubId( 739 contextHubId, transactionCallback, ContextHubTransaction.TYPE_QUERY_NANOAPPS)) { 740 return; 741 } 742 743 ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( 744 contextHubId, transactionCallback); 745 mTransactionManager.addTransaction(transaction); 746 } 747 748 @Override 749 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 750 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 751 752 pw.println("Dumping ContextHub Service"); 753 754 pw.println(""); 755 // dump ContextHubInfo 756 pw.println("=================== CONTEXT HUBS ===================="); 757 for (ContextHubInfo hubInfo : mContextHubIdToInfoMap.values()) { 758 pw.println(hubInfo); 759 } 760 pw.println(""); 761 pw.println("=================== NANOAPPS ===================="); 762 // Dump nanoAppHash 763 for (NanoAppInstanceInfo info : mNanoAppStateManager.getNanoAppInstanceInfoCollection()) { 764 pw.println(info); 765 } 766 767 // dump eventLog 768 } 769 770 private void checkPermissions() { 771 ContextHubServiceUtil.checkPermissions(mContext); 772 } 773 774 private int onMessageReceiptOldApi( 775 int msgType, int contextHubHandle, int appInstance, byte[] data) { 776 if (data == null) { 777 return -1; 778 } 779 780 int msgVersion = 0; 781 int callbacksCount = mCallbacksList.beginBroadcast(); 782 Log.d(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle " + 783 contextHubHandle + ", appInstance " + appInstance + ", callBackCount " 784 + callbacksCount); 785 786 if (callbacksCount < 1) { 787 Log.v(TAG, "No message callbacks registered."); 788 return 0; 789 } 790 791 ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data); 792 for (int i = 0; i < callbacksCount; ++i) { 793 IContextHubCallback callback = mCallbacksList.getBroadcastItem(i); 794 try { 795 callback.onMessageReceipt(contextHubHandle, appInstance, msg); 796 } catch (RemoteException e) { 797 Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ")."); 798 continue; 799 } 800 } 801 mCallbacksList.finishBroadcast(); 802 return 0; 803 } 804 805 /** 806 * Validates the HAL proxy state and context hub ID to see if we can start the transaction. 807 * 808 * @param contextHubId the ID of the hub to start the transaction 809 * @param callback the client transaction callback interface 810 * @param transactionType the type of the transaction 811 * 812 * @return {@code true} if mContextHubProxy and contextHubId is valid, {@code false} otherwise 813 */ 814 private boolean checkHalProxyAndContextHubId( 815 int contextHubId, IContextHubTransactionCallback callback, 816 @ContextHubTransaction.Type int transactionType) { 817 if (mContextHubProxy == null) { 818 try { 819 callback.onTransactionComplete( 820 ContextHubTransaction.RESULT_FAILED_HAL_UNAVAILABLE); 821 } catch (RemoteException e) { 822 Log.e(TAG, "RemoteException while calling onTransactionComplete", e); 823 } 824 return false; 825 } 826 if (!isValidContextHubId(contextHubId)) { 827 Log.e(TAG, "Cannot start " 828 + ContextHubTransaction.typeToString(transactionType, false /* upperCase */) 829 + " transaction for invalid hub ID " + contextHubId); 830 try { 831 callback.onTransactionComplete(ContextHubTransaction.RESULT_FAILED_BAD_PARAMS); 832 } catch (RemoteException e) { 833 Log.e(TAG, "RemoteException while calling onTransactionComplete", e); 834 } 835 return false; 836 } 837 838 return true; 839 } 840 } 841