blob: 9640e042fe6a2ca7c578839f62e4b4daab446550 [file] [log] [blame]
/*
* Copyright 2017 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.ContextHubMsg;
import android.hardware.contexthub.V1_0.IContexthub;
import android.hardware.contexthub.V1_0.Result;
import android.hardware.location.ContextHubTransaction;
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* A class that acts as a broker for the ContextHubClient, which handles messaging and life-cycle
* notification callbacks. This class implements the IContextHubClient object, and the implemented
* APIs must be thread-safe.
*
* @hide
*/
public class ContextHubClientBroker extends IContextHubClient.Stub
implements IBinder.DeathRecipient {
private static final String TAG = "ContextHubClientBroker";
/*
* The context of the service.
*/
private final Context mContext;
/*
* The proxy to talk to the Context Hub HAL.
*/
private final IContexthub mContextHubProxy;
/*
* The manager that registered this client.
*/
private final ContextHubClientManager mClientManager;
/*
* The ID of the hub that this client is attached to.
*/
private final int mAttachedContextHubId;
/*
* The host end point ID of this client.
*/
private final short mHostEndPointId;
/*
* The remote callback interface for this client.
*/
private final IContextHubClientCallback mCallbackInterface;
/*
* false if the connection has been closed by the client, true otherwise.
*/
private final AtomicBoolean mConnectionOpen = new AtomicBoolean(true);
/* package */ ContextHubClientBroker(
Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
int contextHubId, short hostEndPointId, IContextHubClientCallback callback) {
mContext = context;
mContextHubProxy = contextHubProxy;
mClientManager = clientManager;
mAttachedContextHubId = contextHubId;
mHostEndPointId = hostEndPointId;
mCallbackInterface = callback;
}
/**
* Attaches a death recipient for this client
*
* @throws RemoteException if the client has already died
*/
/* package */ void attachDeathRecipient() throws RemoteException {
mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
}
/**
* Sends from this client to a nanoapp.
*
* @param message the message to send
* @return the error code of sending the message
*/
@ContextHubTransaction.Result
@Override
public int sendMessageToNanoApp(NanoAppMessage message) {
ContextHubServiceUtil.checkPermissions(mContext);
int result;
if (mConnectionOpen.get()) {
ContextHubMsg messageToNanoApp = ContextHubServiceUtil.createHidlContextHubMessage(
mHostEndPointId, message);
try {
result = mContextHubProxy.sendMessageToHub(mAttachedContextHubId, messageToNanoApp);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in sendMessageToNanoApp (target hub ID = "
+ mAttachedContextHubId + ")", e);
result = Result.UNKNOWN_FAILURE;
}
} else {
Log.e(TAG, "Failed to send message to nanoapp: client connection is closed");
result = Result.UNKNOWN_FAILURE;
}
return ContextHubServiceUtil.toTransactionResult(result);
}
/**
* Closes the connection for this client with the service.
*/
@Override
public void close() {
if (mConnectionOpen.getAndSet(false)) {
mClientManager.unregisterClient(mHostEndPointId);
}
}
/**
* Invoked when the underlying binder of this broker has died at the client process.
*/
public void binderDied() {
try {
IContextHubClient.Stub.asInterface(this).close();
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while closing client on death", e);
}
}
/**
* @return the ID of the context hub this client is attached to
*/
/* package */ int getAttachedContextHubId() {
return mAttachedContextHubId;
}
/**
* @return the host endpoint ID of this client
*/
/* package */ short getHostEndPointId() {
return mHostEndPointId;
}
/**
* Sends a message to the client associated with this object.
*
* @param message the message that came from a nanoapp
*/
/* package */ void sendMessageToClient(NanoAppMessage message) {
if (mConnectionOpen.get()) {
try {
mCallbackInterface.onMessageFromNanoApp(message);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while sending message to client (host endpoint ID = "
+ mHostEndPointId + ")", e);
}
}
}
/**
* Notifies the client of a nanoapp load event if the connection is open.
*
* @param nanoAppId the ID of the nanoapp that was loaded.
*/
/* package */ void onNanoAppLoaded(long nanoAppId) {
if (mConnectionOpen.get()) {
try {
mCallbackInterface.onNanoAppLoaded(nanoAppId);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while calling onNanoAppLoaded on client"
+ " (host endpoint ID = " + mHostEndPointId + ")", e);
}
}
}
/**
* Notifies the client of a nanoapp unload event if the connection is open.
*
* @param nanoAppId the ID of the nanoapp that was unloaded.
*/
/* package */ void onNanoAppUnloaded(long nanoAppId) {
if (mConnectionOpen.get()) {
try {
mCallbackInterface.onNanoAppUnloaded(nanoAppId);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while calling onNanoAppUnloaded on client"
+ " (host endpoint ID = " + mHostEndPointId + ")", e);
}
}
}
/**
* Notifies the client of a hub reset event if the connection is open.
*/
/* package */ void onHubReset() {
if (mConnectionOpen.get()) {
try {
mCallbackInterface.onHubReset();
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while calling onHubReset on client" +
" (host endpoint ID = " + mHostEndPointId + ")", e);
}
}
}
/**
* Notifies the client of a nanoapp abort event if the connection is open.
*
* @param nanoAppId the ID of the nanoapp that aborted
* @param abortCode the nanoapp specific abort code
*/
/* package */ void onNanoAppAborted(long nanoAppId, int abortCode) {
if (mConnectionOpen.get()) {
try {
mCallbackInterface.onNanoAppAborted(nanoAppId, abortCode);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException while calling onNanoAppAborted on client"
+ " (host endpoint ID = " + mHostEndPointId + ")", e);
}
}
}
}