blob: e08c65967b32a1907dcee12d210380ad44f05a72 [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.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;
import java.util.concurrent.ConcurrentHashMap;
/**
* @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 String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
private static final int PRE_LOADED_APP_MEM_REQ = 0;
private static final int OS_APP_INSTANCE = -1;
private final Context mContext;
// TODO(b/69270990): Remove once old ContextHubManager API is deprecated
// Service cache maintaining of instance ID to nanoapp infos
private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
new ConcurrentHashMap<>();
// The next available instance ID (managed by the service) to assign to a nanoapp
private int mNextAvailableInstanceId = 0;
// A map of the long nanoapp ID to instance ID managed by the service
private final ConcurrentHashMap<Long, Integer> mNanoAppIdToInstanceMap =
new ConcurrentHashMap<>();
private final ContextHubInfo[] mContextHubInfo;
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;
/**
* 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.EMPTY_MAP;
mContextHubInfo = new ContextHubInfo[0];
return;
}
mClientManager = new ContextHubClientManager(mContext, mContextHubProxy);
mTransactionManager = new ContextHubTransactionManager(mContextHubProxy, mClientManager);
List<ContextHub> hubList;
try {
hubList = mContextHubProxy.getHubs();
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while getting Context Hub info", e);
hubList = Collections.emptyList();
}
mContextHubInfo = ContextHubServiceUtil.createContextHubInfoArray(hubList);
HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
for (ContextHubInfo contextHubInfo : mContextHubInfo) {
int contextHubId = contextHubInfo.getId();
IContextHubClient client = mClientManager.registerClient(
createDefaultClientCallback(contextHubId), contextHubId);
defaultClientMap.put(contextHubId, client);
}
mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
for (ContextHubInfo contextHubInfo : mContextHubInfo) {
int contextHubId = contextHubInfo.getId();
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
for (ContextHubInfo contextHubInfo : mContextHubInfo) {
queryNanoAppsInternal(contextHubInfo.getId());
}
for (int i = 0; i < mContextHubInfo.length; i++) {
Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
+ ", name: " + mContextHubInfo[i].getName());
}
}
/**
* 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 nanoAppInstanceId =
mNanoAppIdToInstanceMap.containsKey(message.getNanoAppId()) ?
mNanoAppIdToInstanceMap.get(message.getNanoAppId()) : -1;
onMessageReceiptOldApi(
message.getMessageType(), contextHubId, nanoAppInstanceId,
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();
int[] returnArray = new int[mContextHubInfo.length];
Log.d(TAG, "System supports " + returnArray.length + " hubs");
for (int i = 0; i < returnArray.length; ++i) {
returnArray[i] = i;
Log.d(TAG, String.format("Hub %s is mapped to %d",
mContextHubInfo[i].getName(), returnArray[i]));
}
return returnArray;
}
@Override
public ContextHubInfo getContextHubInfo(int contextHubId) throws RemoteException {
checkPermissions();
if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
Log.e(TAG, "Invalid context hub handle " + contextHubId);
return null; // null means fail
}
return mContextHubInfo[contextHubId];
}
/**
* 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
* @param nanoAppId the ID of the nanoapp to unload
* @return the callback interface
*/
private IContextHubTransactionCallback createUnloadTransactionCallback(
int contextHubId, long nanoAppId) {
return new IContextHubTransactionCallback.Stub() {
@Override
public void onTransactionComplete(int result) {
handleUnloadResponseOldApi(contextHubId, result, nanoAppId);
}
@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);
}
};
}
/**
* Adds a new transaction to the transaction manager queue
*
* @param transaction the transaction to add
* @return the result of adding the transaction
*/
private int addTransaction(ContextHubServiceTransaction transaction) {
int result = Result.OK;
try {
mTransactionManager.addTransaction(transaction);
} catch (IllegalStateException e) {
Log.e(TAG, e.getMessage());
result = Result.TRANSACTION_PENDING; /* failed */
}
return result;
}
@Override
public int loadNanoApp(int contextHubId, NanoApp app) throws RemoteException {
checkPermissions();
if (mContextHubProxy == null) {
return -1;
}
if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
Log.e(TAG, "Invalid contextHubhandle " + contextHubId);
return -1;
}
if (app == null) {
Log.e(TAG, "Invalid null app");
return -1;
}
// Create an internal IContextHubTransactionCallback for the old API clients
NanoAppBinary nanoAppBinary = new NanoAppBinary(app.getAppBinary());
IContextHubTransactionCallback onCompleteCallback =
createLoadTransactionCallback(contextHubId, nanoAppBinary);
ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
contextHubId, nanoAppBinary, onCompleteCallback);
int result = addTransaction(transaction);
if (result != Result.OK) {
Log.e(TAG, "Failed to load nanoapp with error code " + result);
return -1;
}
// Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
return 0;
}
@Override
public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
checkPermissions();
if (mContextHubProxy == null) {
return -1;
}
NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
if (info == null) {
Log.e(TAG, "Cannot find app with handle " + nanoAppInstanceHandle);
return -1; //means failed
}
int contextHubId = info.getContexthubId();
long nanoAppId = info.getAppId();
IContextHubTransactionCallback onCompleteCallback =
createUnloadTransactionCallback(contextHubId, nanoAppId);
ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
contextHubId, nanoAppId, onCompleteCallback);
int result = addTransaction(transaction);
if (result != Result.OK) {
Log.e(TAG, "Failed to unload nanoapp with error code " + result);
return -1;
}
// Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
return 0;
}
@Override
public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
throws RemoteException {
checkPermissions();
// This assumes that all the nanoAppInfo is current. This is reasonable
// for the use cases for tightly controlled nanoApps.
if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
return mNanoAppHash.get(nanoAppInstanceHandle);
} else {
Log.e(TAG, "Could not find nanoApp with handle " + nanoAppInstanceHandle);
return null;
}
}
@Override
public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
checkPermissions();
ArrayList<Integer> foundInstances = new ArrayList<Integer>();
for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
if (filter.testMatch(info)) {
foundInstances.add(nanoAppInstance);
}
}
int[] retArray = new int[foundInstances.size()];
for (int i = 0; i < foundInstances.size(); i++) {
retArray[i] = foundInstances.get(i).intValue();
}
Log.w(TAG, "Found " + retArray.length + " apps on hub handle " + hubHandle);
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
*/
private int queryNanoAppsInternal(int contextHubId) {
if (mContextHubProxy == null) {
return Result.UNKNOWN_FAILURE;
}
IContextHubTransactionCallback onCompleteCallback =
createQueryTransactionCallback(contextHubId);
ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
contextHubId, onCompleteCallback);
return addTransaction(transaction);
}
@Override
public int sendMessage(
int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
checkPermissions();
if (mContextHubProxy == null) {
return -1;
}
if (msg == null) {
Log.e(TAG, "ContextHubMessage cannot be null");
return -1;
}
if (msg.getData() == null) {
Log.e(TAG, "ContextHubMessage message body cannot be null");
return -1;
}
if (!mDefaultClientMap.containsKey(hubHandle)) {
Log.e(TAG, "Hub with ID " + hubHandle + " does not exist");
return -1;
}
boolean success = false;
if (nanoAppHandle == OS_APP_INSTANCE) {
if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
success = (queryNanoAppsInternal(hubHandle) == 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(hubHandle);
success = (client.sendMessageToNanoApp(message) ==
ContextHubTransaction.TRANSACTION_SUCCESS);
} else {
Log.e(TAG, "Failed to send nanoapp message - nanoapp with instance ID "
+ 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;
}
// NOTE: The legacy JNI code used to do a query right after a load success
// to synchronize the service cache. Instead store the binary that was requested to
// load to update the cache later without doing a query.
int instanceId = 0;
long nanoAppId = nanoAppBinary.getNanoAppId();
int nanoAppVersion = nanoAppBinary.getNanoAppVersion();
if (result == TransactionResult.SUCCESS) {
if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
} else {
instanceId = mNextAvailableInstanceId++;
mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
}
addAppInstance(contextHubId, instanceId, nanoAppId, nanoAppVersion);
}
byte[] data = new byte[5];
data[0] = (byte) result;
ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(instanceId);
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, long nanoAppId) {
if (result == TransactionResult.SUCCESS) {
int instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
deleteAppInstance(instanceId);
mNanoAppIdToInstanceMap.remove(nanoAppId);
}
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) {
// TODO(b/31049861): Implement this
}
/**
* 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);
updateServiceCache(contextHubId, nanoAppInfoList);
mTransactionManager.onQueryResponse(nanoAppStateList);
}
/**
* Updates the service's cache of the list of loaded nanoapps using a nanoapp list response.
*
* TODO(b/69270990): Remove this when the old API functionality is removed.
*
* @param contextHubId the ID of the hub the response came from
* @param nanoAppInfoList the list of loaded nanoapps
*/
private void updateServiceCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
synchronized (mNanoAppHash) {
for (int instanceId : mNanoAppHash.keySet()) {
if (mNanoAppHash.get(instanceId).getContexthubId() == contextHubId) {
deleteAppInstance(instanceId);
}
}
for (HubAppInfo appInfo : nanoAppInfoList) {
int instanceId;
long nanoAppId = appInfo.appId;
if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
} else {
instanceId = mNextAvailableInstanceId++;
mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
}
addAppInstance(contextHubId, instanceId, nanoAppId, appInfo.version);
}
}
}
/**
* @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) {
for (ContextHubInfo hubInfo : mContextHubInfo) {
if (hubInfo.getId() == contextHubId) {
return true;
}
}
return false;
}
/**
* Creates and registers a client at the service for the specified Context Hub.
*
* @param clientCallback the client interface to register with the service
* @param contextHubId the ID of the hub this client is attached to
* @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(
IContextHubClientCallback clientCallback, int contextHubId) 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");
}
return mClientManager.registerClient(clientCallback, contextHubId);
}
@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 (int i = 0; i < mContextHubInfo.length; i++) {
pw.println("Handle " + i + " : " + mContextHubInfo[i].toString());
}
pw.println("");
pw.println("=================== NANOAPPS ====================");
// Dump nanoAppHash
for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
}
// dump eventLog
}
private void checkPermissions() {
ContextHubServiceUtil.checkPermissions(mContext);
}
private int onMessageReceiptOldApi(int msgType, int hubHandle, int appInstance, byte[] data) {
if (data == null) {
return -1;
}
int msgVersion = 0;
int callbacksCount = mCallbacksList.beginBroadcast();
Log.d(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle " +
hubHandle + ", appInstance " + appInstance + ", callBackCount " + callbacksCount);
if (callbacksCount < 1) {
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(hubHandle, appInstance, msg);
} catch (RemoteException e) {
Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
continue;
}
}
mCallbacksList.finishBroadcast();
return 0;
}
private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
// App Id encodes vendor & version
NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
appInfo.setAppId(appId);
appInfo.setAppVersion(appVersion);
appInfo.setName(PRE_LOADED_APP_NAME);
appInfo.setContexthubId(hubHandle);
appInfo.setHandle(appInstanceHandle);
appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
String action;
if (mNanoAppHash.containsKey(appInstanceHandle)) {
action = "Updated";
} else {
action = "Added";
}
mNanoAppHash.put(appInstanceHandle, appInfo);
Log.d(TAG, action + " app instance " + appInstanceHandle + " with id 0x"
+ Long.toHexString(appId) + " version 0x" + Integer.toHexString(appVersion));
return 0;
}
private int deleteAppInstance(int appInstanceHandle) {
if (mNanoAppHash.remove(appInstanceHandle) == null) {
return -1;
}
return 0;
}
}