blob: 36b0342c21d83215a1deb648f107b02824322d9b [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.location;
import android.app.PendingIntent;
import android.content.Context;
import android.hardware.contexthub.V1_0.AsyncEventType;
import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.HubAppInfo;
import android.hardware.contexthub.V1_0.IContexthub;
import android.hardware.contexthub.V1_0.IContexthubCallback;
import android.hardware.contexthub.V1_0.Result;
import android.hardware.contexthub.V1_0.TransactionResult;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubMessage;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.IContextHubCallback;
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.IContextHubService;
import android.hardware.location.IContextHubTransactionCallback;
import android.hardware.location.NanoApp;
import android.hardware.location.NanoAppBinary;
import android.hardware.location.NanoAppFilter;
import android.hardware.location.NanoAppInstanceInfo;
import android.hardware.location.NanoAppMessage;
import android.hardware.location.NanoAppState;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import com.android.internal.util.DumpUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
/**
* @hide
*/
public class ContextHubService extends IContextHubService.Stub {
private static final String TAG = "ContextHubService";
/*
* Constants for the type of transaction that is defined by ContextHubService.
* This is used to report the transaction callback to clients, and is different from
* ContextHubTransaction.Type.
*/
public static final int MSG_ENABLE_NANO_APP = 1;
public static final int MSG_DISABLE_NANO_APP = 2;
public static final int MSG_LOAD_NANO_APP = 3;
public static final int MSG_UNLOAD_NANO_APP = 4;
public static final int MSG_QUERY_NANO_APPS = 5;
public static final int MSG_QUERY_MEMORY = 6;
public static final int MSG_HUB_RESET = 7;
private static final int OS_APP_INSTANCE = -1;
/*
* Local flag to enable debug logging.
*/
private static final boolean DEBUG_LOG_ENABLED = false;
private final Context mContext;
private final Map<Integer, ContextHubInfo> mContextHubIdToInfoMap;
private final List<ContextHubInfo> mContextHubInfoList;
private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
new RemoteCallbackList<>();
// Proxy object to communicate with the Context Hub HAL
private final IContexthub mContextHubProxy;
// The manager for transaction queue
private final ContextHubTransactionManager mTransactionManager;
// The manager for sending messages to/from clients
private final ContextHubClientManager mClientManager;
// The default client for old API clients
private final Map<Integer, IContextHubClient> mDefaultClientMap;
// The manager for the internal nanoapp state cache
private final NanoAppStateManager mNanoAppStateManager = new NanoAppStateManager();
/**
* Class extending the callback to register with a Context Hub.
*/
private class ContextHubServiceCallback extends IContexthubCallback.Stub {
private final int mContextHubId;
ContextHubServiceCallback(int contextHubId) {
mContextHubId = contextHubId;
}
@Override
public void handleClientMsg(ContextHubMsg message) {
handleClientMessageCallback(mContextHubId, message);
}
@Override
public void handleTxnResult(int transactionId, int result) {
handleTransactionResultCallback(mContextHubId, transactionId, result);
}
@Override
public void handleHubEvent(int eventType) {
handleHubEventCallback(mContextHubId, eventType);
}
@Override
public void handleAppAbort(long nanoAppId, int abortCode) {
handleAppAbortCallback(mContextHubId, nanoAppId, abortCode);
}
@Override
public void handleAppsInfo(ArrayList<HubAppInfo> nanoAppInfoList) {
handleQueryAppsCallback(mContextHubId, nanoAppInfoList);
}
}
public ContextHubService(Context context) {
mContext = context;
mContextHubProxy = getContextHubProxy();
if (mContextHubProxy == null) {
mTransactionManager = null;
mClientManager = null;
mDefaultClientMap = Collections.emptyMap();
mContextHubIdToInfoMap = Collections.emptyMap();
mContextHubInfoList = Collections.emptyList();
return;
}
mClientManager = new ContextHubClientManager(mContext, mContextHubProxy);
mTransactionManager = new ContextHubTransactionManager(
mContextHubProxy, mClientManager, mNanoAppStateManager);
List<ContextHub> hubList;
try {
hubList = mContextHubProxy.getHubs();
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while getting Context Hub info", e);
hubList = Collections.emptyList();
}
mContextHubIdToInfoMap = Collections.unmodifiableMap(
ContextHubServiceUtil.createContextHubInfoMap(hubList));
mContextHubInfoList = new ArrayList<>(mContextHubIdToInfoMap.values());
HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
IContextHubClient client = mClientManager.registerClient(
contextHubInfo, createDefaultClientCallback(contextHubId));
defaultClientMap.put(contextHubId, client);
try {
mContextHubProxy.registerCallback(
contextHubId, new ContextHubServiceCallback(contextHubId));
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while registering service callback for hub (ID = "
+ contextHubId + ")", e);
}
// Do a query to initialize the service cache list of nanoapps
// TODO(b/69270990): Remove this when old API is deprecated
queryNanoAppsInternal(contextHubId);
}
mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
}
/**
* Creates a default client callback for old API clients.
*
* @param contextHubId the ID of the hub to attach this client to
* @return the internal callback interface
*/
private IContextHubClientCallback createDefaultClientCallback(int contextHubId) {
return new IContextHubClientCallback.Stub() {
@Override
public void onMessageFromNanoApp(NanoAppMessage message) {
int nanoAppHandle = mNanoAppStateManager.getNanoAppHandle(
contextHubId, message.getNanoAppId());
onMessageReceiptOldApi(
message.getMessageType(), contextHubId, nanoAppHandle,
message.getMessageBody());
}
@Override
public void onHubReset() {
byte[] data = {TransactionResult.SUCCESS};
onMessageReceiptOldApi(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
}
@Override
public void onNanoAppAborted(long nanoAppId, int abortCode) {
}
@Override
public void onNanoAppLoaded(long nanoAppId) {
}
@Override
public void onNanoAppUnloaded(long nanoAppId) {
}
@Override
public void onNanoAppEnabled(long nanoAppId) {
}
@Override
public void onNanoAppDisabled(long nanoAppId) {
}
};
}
/**
* @return the IContexthub proxy interface
*/
private IContexthub getContextHubProxy() {
IContexthub proxy = null;
try {
proxy = IContexthub.getService(true /* retry */);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy", e);
} catch (NoSuchElementException e) {
Log.i(TAG, "Context Hub HAL service not found");
}
return proxy;
}
@Override
public int registerCallback(IContextHubCallback callback) throws RemoteException {
checkPermissions();
mCallbacksList.register(callback);
Log.d(TAG, "Added callback, total callbacks " +
mCallbacksList.getRegisteredCallbackCount());
return 0;
}
@Override
public int[] getContextHubHandles() throws RemoteException {
checkPermissions();
return ContextHubServiceUtil.createPrimitiveIntArray(mContextHubIdToInfoMap.keySet());
}
@Override
public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
checkPermissions();
if (!mContextHubIdToInfoMap.containsKey(contextHubHandle)) {
Log.e(TAG, "Invalid Context Hub handle " + contextHubHandle + " in getContextHubInfo");
return null;
}
return mContextHubIdToInfoMap.get(contextHubHandle);
}
/**
* Returns a List of ContextHubInfo object describing the available hubs.
*
* @return the List of ContextHubInfo objects
*/
@Override
public List<ContextHubInfo> getContextHubs() throws RemoteException {
checkPermissions();
return mContextHubInfoList;
}
/**
* Creates an internal load transaction callback to be used for old API clients
*
* @param contextHubId the ID of the hub to load the binary
* @param nanoAppBinary the binary to load
* @return the callback interface
*/
private IContextHubTransactionCallback createLoadTransactionCallback(
int contextHubId, NanoAppBinary nanoAppBinary) {
return new IContextHubTransactionCallback.Stub() {
@Override
public void onTransactionComplete(int result) {
handleLoadResponseOldApi(contextHubId, result, nanoAppBinary);
}
@Override
public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
}
};
}
/**
* Creates an internal unload transaction callback to be used for old API clients
*
* @param contextHubId the ID of the hub to unload the nanoapp
* @return the callback interface
*/
private IContextHubTransactionCallback createUnloadTransactionCallback(int contextHubId) {
return new IContextHubTransactionCallback.Stub() {
@Override
public void onTransactionComplete(int result) {
handleUnloadResponseOldApi(contextHubId, result);
}
@Override
public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
}
};
}
/**
* Creates an internal query transaction callback to be used for old API clients
*
* @param contextHubId the ID of the hub to query
* @return the callback interface
*/
private IContextHubTransactionCallback createQueryTransactionCallback(int contextHubId) {
return new IContextHubTransactionCallback.Stub() {
@Override
public void onTransactionComplete(int result) {
}
@Override
public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
byte[] data = {(byte) result};
onMessageReceiptOldApi(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data);
}
};
}
@Override
public int loadNanoApp(int contextHubHandle, NanoApp nanoApp) throws RemoteException {
checkPermissions();
if (mContextHubProxy == null) {
return -1;
}
if (!isValidContextHubId(contextHubHandle)) {
Log.e(TAG, "Invalid Context Hub handle " + contextHubHandle + " in loadNanoApp");
return -1;
}
if (nanoApp == null) {
Log.e(TAG, "NanoApp cannot be null in loadNanoApp");
return -1;
}
// Create an internal IContextHubTransactionCallback for the old API clients
NanoAppBinary nanoAppBinary = new NanoAppBinary(nanoApp.getAppBinary());
IContextHubTransactionCallback onCompleteCallback =
createLoadTransactionCallback(contextHubHandle, nanoAppBinary);
ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
contextHubHandle, nanoAppBinary, onCompleteCallback);
mTransactionManager.addTransaction(transaction);
return 0;
}
@Override
public int unloadNanoApp(int nanoAppHandle) throws RemoteException {
checkPermissions();
if (mContextHubProxy == null) {
return -1;
}
NanoAppInstanceInfo info =
mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle);
if (info == null) {
Log.e(TAG, "Invalid nanoapp handle " + nanoAppHandle + " in unloadNanoApp");
return -1;
}
int contextHubId = info.getContexthubId();
long nanoAppId = info.getAppId();
IContextHubTransactionCallback onCompleteCallback =
createUnloadTransactionCallback(contextHubId);
ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
contextHubId, nanoAppId, onCompleteCallback);
mTransactionManager.addTransaction(transaction);
return 0;
}
@Override
public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) throws RemoteException {
checkPermissions();
return mNanoAppStateManager.getNanoAppInstanceInfo(nanoAppHandle);
}
@Override
public int[] findNanoAppOnHub(
int contextHubHandle, NanoAppFilter filter) throws RemoteException {
checkPermissions();
ArrayList<Integer> foundInstances = new ArrayList<>();
if (filter != null) {
mNanoAppStateManager.foreachNanoAppInstanceInfo((info) -> {
if (filter.testMatch(info)) {
foundInstances.add(info.getHandle());
}
});
}
int[] retArray = new int[foundInstances.size()];
for (int i = 0; i < foundInstances.size(); i++) {
retArray[i] = foundInstances.get(i).intValue();
}
return retArray;
}
/**
* Performs a query at the specified hub.
*
* This method should only be invoked internally by the service, either to update the service
* cache or as a result of an explicit query requested by a client through the sendMessage API.
*
* @param contextHubId the ID of the hub to do the query
* @return the result of the query
*
* @throws IllegalStateException if the transaction queue is full
*/
private int queryNanoAppsInternal(int contextHubId) {
if (mContextHubProxy == null) {
return Result.UNKNOWN_FAILURE;
}
IContextHubTransactionCallback onCompleteCallback =
createQueryTransactionCallback(contextHubId);
ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
contextHubId, onCompleteCallback);
mTransactionManager.addTransaction(transaction);
return Result.OK;
}
@Override
public int sendMessage(int contextHubHandle, int nanoAppHandle, ContextHubMessage msg)
throws RemoteException {
checkPermissions();
if (mContextHubProxy == null) {
return -1;
}
if (msg == null) {
Log.e(TAG, "ContextHubMessage cannot be null in sendMessage");
return -1;
}
if (msg.getData() == null) {
Log.e(TAG, "ContextHubMessage message body cannot be null in sendMessage");
return -1;
}
if (!isValidContextHubId(contextHubHandle)) {
Log.e(TAG, "Invalid Context Hub handle " + contextHubHandle + " in sendMessage");
return -1;
}
boolean success = false;
if (nanoAppHandle == OS_APP_INSTANCE) {
if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
success = (queryNanoAppsInternal(contextHubHandle) == Result.OK);
} else {
Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType());
}
} else {
NanoAppInstanceInfo info = getNanoAppInstanceInfo(nanoAppHandle);
if (info != null) {
NanoAppMessage message = NanoAppMessage.createMessageToNanoApp(
info.getAppId(), msg.getMsgType(), msg.getData());
IContextHubClient client = mDefaultClientMap.get(contextHubHandle);
success = (client.sendMessageToNanoApp(message) ==
ContextHubTransaction.RESULT_SUCCESS);
} else {
Log.e(TAG, "Failed to send nanoapp message - nanoapp with handle "
+ nanoAppHandle + " does not exist.");
}
}
return success ? 0 : -1;
}
/**
* Handles a unicast or broadcast message from a nanoapp.
*
* @param contextHubId the ID of the hub the message came from
* @param message the message contents
*/
private void handleClientMessageCallback(int contextHubId, ContextHubMsg message) {
mClientManager.onMessageFromNanoApp(contextHubId, message);
}
/**
* A helper function to handle a load response from the Context Hub for the old API.
*
* TODO(b/69270990): Remove this once the old APIs are obsolete.
*/
private void handleLoadResponseOldApi(
int contextHubId, int result, NanoAppBinary nanoAppBinary) {
if (nanoAppBinary == null) {
Log.e(TAG, "Nanoapp binary field was null for a load transaction");
return;
}
byte[] data = new byte[5];
data[0] = (byte) result;
int nanoAppHandle = mNanoAppStateManager.getNanoAppHandle(
contextHubId, nanoAppBinary.getNanoAppId());
ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(nanoAppHandle);
onMessageReceiptOldApi(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
}
/**
* A helper function to handle an unload response from the Context Hub for the old API.
*
* TODO(b/69270990): Remove this once the old APIs are obsolete.
*/
private void handleUnloadResponseOldApi(int contextHubId, int result) {
byte[] data = new byte[1];
data[0] = (byte) result;
onMessageReceiptOldApi(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
}
/**
* Handles a transaction response from a Context Hub.
*
* @param contextHubId the ID of the hub the response came from
* @param transactionId the ID of the transaction
* @param result the result of the transaction reported by the hub
*/
private void handleTransactionResultCallback(int contextHubId, int transactionId, int result) {
mTransactionManager.onTransactionResponse(transactionId, result);
}
/**
* Handles an asynchronous event from a Context Hub.
*
* @param contextHubId the ID of the hub the response came from
* @param eventType the type of the event as defined in Context Hub HAL AsyncEventType
*/
private void handleHubEventCallback(int contextHubId, int eventType) {
if (eventType == AsyncEventType.RESTARTED) {
mTransactionManager.onHubReset();
queryNanoAppsInternal(contextHubId);
mClientManager.onHubReset(contextHubId);
} else {
Log.i(TAG, "Received unknown hub event (hub ID = " + contextHubId + ", type = "
+ eventType + ")");
}
}
/**
* Handles an asynchronous abort event of a nanoapp.
*
* @param contextHubId the ID of the hub that the nanoapp aborted in
* @param nanoAppId the ID of the aborted nanoapp
* @param abortCode the nanoapp-specific abort code
*/
private void handleAppAbortCallback(int contextHubId, long nanoAppId, int abortCode) {
mClientManager.onNanoAppAborted(contextHubId, nanoAppId, abortCode);
}
/**
* Handles a query response from a Context Hub.
*
* @param contextHubId the ID of the hub of the response
* @param nanoAppInfoList the list of loaded nanoapps
*/
private void handleQueryAppsCallback(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
List<NanoAppState> nanoAppStateList =
ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
mNanoAppStateManager.updateCache(contextHubId, nanoAppInfoList);
mTransactionManager.onQueryResponse(nanoAppStateList);
}
/**
* @param contextHubId the hub ID to validate
* @return {@code true} if the ID represents that of an available hub, {@code false} otherwise
*/
private boolean isValidContextHubId(int contextHubId) {
return mContextHubIdToInfoMap.containsKey(contextHubId);
}
/**
* Creates and registers a client at the service for the specified Context Hub.
*
* @param contextHubId the ID of the hub this client is attached to
* @param clientCallback the client interface to register with the service
* @return the generated client interface, null if registration was unsuccessful
*
* @throws IllegalArgumentException if contextHubId is not a valid ID
* @throws IllegalStateException if max number of clients have already registered
* @throws NullPointerException if clientCallback is null
*/
@Override
public IContextHubClient createClient(
int contextHubId, IContextHubClientCallback clientCallback) throws RemoteException {
checkPermissions();
if (!isValidContextHubId(contextHubId)) {
throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
}
if (clientCallback == null) {
throw new NullPointerException("Cannot register client with null callback");
}
ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
return mClientManager.registerClient(contextHubInfo, clientCallback);
}
/**
* Creates and registers a PendingIntent client at the service for the specified Context Hub.
*
* @param contextHubId the ID of the hub this client is attached to
* @param pendingIntent the PendingIntent associated with this client
* @param nanoAppId the ID of the nanoapp PendingIntent events will be sent for
* @return the generated client interface
*
* @throws IllegalArgumentException if hubInfo does not represent a valid hub
* @throws IllegalStateException if there were too many registered clients at the service
*/
@Override
public IContextHubClient createPendingIntentClient(
int contextHubId, PendingIntent pendingIntent, long nanoAppId) throws RemoteException {
checkPermissions();
if (!isValidContextHubId(contextHubId)) {
throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
}
ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
return mClientManager.registerClient(contextHubInfo, pendingIntent, nanoAppId);
}
/**
* Loads a nanoapp binary at the specified Context hub.
*
* @param contextHubId the ID of the hub to load the binary
* @param transactionCallback the client-facing transaction callback interface
* @param nanoAppBinary the binary to load
*
* @throws IllegalStateException if the transaction queue is full
*/
@Override
public void loadNanoAppOnHub(
int contextHubId, IContextHubTransactionCallback transactionCallback,
NanoAppBinary nanoAppBinary) throws RemoteException {
checkPermissions();
if (!checkHalProxyAndContextHubId(
contextHubId, transactionCallback, ContextHubTransaction.TYPE_LOAD_NANOAPP)) {
return;
}
if (nanoAppBinary == null) {
Log.e(TAG, "NanoAppBinary cannot be null in loadNanoAppOnHub");
transactionCallback.onTransactionComplete(
ContextHubTransaction.RESULT_FAILED_BAD_PARAMS);
return;
}
ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
contextHubId, nanoAppBinary, transactionCallback);
mTransactionManager.addTransaction(transaction);
}
/**
* Unloads a nanoapp from the specified Context Hub.
*
* @param contextHubId the ID of the hub to unload the nanoapp
* @param transactionCallback the client-facing transaction callback interface
* @param nanoAppId the ID of the nanoapp to unload
*
* @throws IllegalStateException if the transaction queue is full
*/
@Override
public void unloadNanoAppFromHub(
int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId)
throws RemoteException {
checkPermissions();
if (!checkHalProxyAndContextHubId(
contextHubId, transactionCallback, ContextHubTransaction.TYPE_UNLOAD_NANOAPP)) {
return;
}
ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
contextHubId, nanoAppId, transactionCallback);
mTransactionManager.addTransaction(transaction);
}
/**
* Enables a nanoapp at the specified Context Hub.
*
* @param contextHubId the ID of the hub to enable the nanoapp
* @param transactionCallback the client-facing transaction callback interface
* @param nanoAppId the ID of the nanoapp to enable
*
* @throws IllegalStateException if the transaction queue is full
*/
@Override
public void enableNanoApp(
int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId)
throws RemoteException {
checkPermissions();
if (!checkHalProxyAndContextHubId(
contextHubId, transactionCallback, ContextHubTransaction.TYPE_ENABLE_NANOAPP)) {
return;
}
ContextHubServiceTransaction transaction = mTransactionManager.createEnableTransaction(
contextHubId, nanoAppId, transactionCallback);
mTransactionManager.addTransaction(transaction);
}
/**
* Disables a nanoapp at the specified Context Hub.
*
* @param contextHubId the ID of the hub to disable the nanoapp
* @param transactionCallback the client-facing transaction callback interface
* @param nanoAppId the ID of the nanoapp to disable
*
* @throws IllegalStateException if the transaction queue is full
*/
@Override
public void disableNanoApp(
int contextHubId, IContextHubTransactionCallback transactionCallback, long nanoAppId)
throws RemoteException {
checkPermissions();
if (!checkHalProxyAndContextHubId(
contextHubId, transactionCallback, ContextHubTransaction.TYPE_DISABLE_NANOAPP)) {
return;
}
ContextHubServiceTransaction transaction = mTransactionManager.createDisableTransaction(
contextHubId, nanoAppId, transactionCallback);
mTransactionManager.addTransaction(transaction);
}
/**
* Queries for a list of nanoapps from the specified Context hub.
*
* @param contextHubId the ID of the hub to query
* @param transactionCallback the client-facing transaction callback interface
*
* @throws IllegalStateException if the transaction queue is full
*/
@Override
public void queryNanoApps(int contextHubId, IContextHubTransactionCallback transactionCallback)
throws RemoteException {
checkPermissions();
if (!checkHalProxyAndContextHubId(
contextHubId, transactionCallback, ContextHubTransaction.TYPE_QUERY_NANOAPPS)) {
return;
}
ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
contextHubId, transactionCallback);
mTransactionManager.addTransaction(transaction);
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
pw.println("Dumping ContextHub Service");
pw.println("");
// dump ContextHubInfo
pw.println("=================== CONTEXT HUBS ====================");
for (ContextHubInfo hubInfo : mContextHubIdToInfoMap.values()) {
pw.println(hubInfo);
}
pw.println("");
pw.println("=================== NANOAPPS ====================");
// Dump nanoAppHash
mNanoAppStateManager.foreachNanoAppInstanceInfo((info) -> pw.println(info));
// dump eventLog
}
private void checkPermissions() {
ContextHubServiceUtil.checkPermissions(mContext);
}
private int onMessageReceiptOldApi(
int msgType, int contextHubHandle, int appInstance, byte[] data) {
if (data == null) {
return -1;
}
int msgVersion = 0;
int callbacksCount = mCallbacksList.beginBroadcast();
if (DEBUG_LOG_ENABLED) {
Log.v(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle "
+ contextHubHandle + ", appInstance " + appInstance + ", callBackCount "
+ callbacksCount);
}
if (callbacksCount < 1) {
if (DEBUG_LOG_ENABLED) {
Log.v(TAG, "No message callbacks registered.");
}
return 0;
}
ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
for (int i = 0; i < callbacksCount; ++i) {
IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
try {
callback.onMessageReceipt(contextHubHandle, appInstance, msg);
} catch (RemoteException e) {
Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
continue;
}
}
mCallbacksList.finishBroadcast();
return 0;
}
/**
* Validates the HAL proxy state and context hub ID to see if we can start the transaction.
*
* @param contextHubId the ID of the hub to start the transaction
* @param callback the client transaction callback interface
* @param transactionType the type of the transaction
*
* @return {@code true} if mContextHubProxy and contextHubId is valid, {@code false} otherwise
*/
private boolean checkHalProxyAndContextHubId(
int contextHubId, IContextHubTransactionCallback callback,
@ContextHubTransaction.Type int transactionType) {
if (mContextHubProxy == null) {
try {
callback.onTransactionComplete(
ContextHubTransaction.RESULT_FAILED_HAL_UNAVAILABLE);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while calling onTransactionComplete", e);
}
return false;
}
if (!isValidContextHubId(contextHubId)) {
Log.e(TAG, "Cannot start "
+ ContextHubTransaction.typeToString(transactionType, false /* upperCase */)
+ " transaction for invalid hub ID " + contextHubId);
try {
callback.onTransactionComplete(ContextHubTransaction.RESULT_FAILED_BAD_PARAMS);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while calling onTransactionComplete", e);
}
return false;
}
return true;
}
}