summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-02-24 15:18:24 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-02-24 15:18:24 -0800
commit0943bee027ee4ffb0aec5ae25f438b3310ac5819 (patch)
tree753032a4bd6c5f5727f6d128f6cf8b679e235706
parentcbcc1dab33e5dae94ac2a4118a7ccb03f24447d0 (diff)
parenta3697593c6d5bbee21d9d0eacd1a0bc01d14b919 (diff)
Merge "Cancel pending reliable message transactions on HAL restart" into main
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java137
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java207
-rw-r--r--services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java76
3 files changed, 296 insertions, 124 deletions
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
index 940bcb4c6ba1..f40d0dd18213 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
@@ -43,7 +43,10 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
/**
* A class that represents a broker for the endpoint registered by the client app. This class
@@ -111,6 +114,11 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
private final boolean mRemoteInitiated;
+ /**
+ * The set of seq # for pending reliable messages started by this endpoint for this session.
+ */
+ private final Set<Integer> mPendingSequenceNumbers = new HashSet<>();
+
SessionInfo(HubEndpointInfo remoteEndpointInfo, boolean remoteInitiated) {
mRemoteEndpointInfo = remoteEndpointInfo;
mRemoteInitiated = remoteInitiated;
@@ -131,6 +139,24 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
public boolean isActive() {
return mSessionState == SessionState.ACTIVE;
}
+
+ public boolean isReliableMessagePending(int sequenceNumber) {
+ return mPendingSequenceNumbers.contains(sequenceNumber);
+ }
+
+ public void setReliableMessagePending(int sequenceNumber) {
+ mPendingSequenceNumbers.add(sequenceNumber);
+ }
+
+ public void setReliableMessageCompleted(int sequenceNumber) {
+ mPendingSequenceNumbers.remove(sequenceNumber);
+ }
+
+ public void forEachPendingReliableMessage(Consumer<Integer> consumer) {
+ for (int sequenceNumber : mPendingSequenceNumbers) {
+ consumer.accept(sequenceNumber);
+ }
+ }
}
/** A map between a session ID which maps to its current state. */
@@ -208,10 +234,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
try {
mSessionInfoMap.put(sessionId, new SessionInfo(destination, false));
mHubInterface.openEndpointSession(
- sessionId,
- halEndpointInfo.id,
- mHalEndpointInfo.id,
- serviceDescriptor);
+ sessionId, halEndpointInfo.id, mHalEndpointInfo.id, serviceDescriptor);
} catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
Log.e(TAG, "Exception while calling HAL openEndpointSession", e);
cleanupSessionResources(sessionId);
@@ -286,34 +309,42 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
public void sendMessage(
int sessionId, HubMessage message, IContextHubTransactionCallback callback) {
super.sendMessage_enforcePermission();
- Message halMessage = ContextHubServiceUtil.createHalMessage(message);
- if (!isSessionActive(sessionId)) {
- throw new SecurityException(
- "sendMessage called on inactive session (id= " + sessionId + ")");
- }
-
- if (callback == null) {
- try {
- mHubInterface.sendMessageToEndpoint(sessionId, halMessage);
- } catch (RemoteException e) {
- Log.w(TAG, "Exception while sending message on session " + sessionId, e);
+ synchronized (mOpenSessionLock) {
+ SessionInfo info = mSessionInfoMap.get(sessionId);
+ if (info == null) {
+ throw new IllegalArgumentException(
+ "sendMessage for invalid session id=" + sessionId);
}
- } else {
- ContextHubServiceTransaction transaction =
- mTransactionManager.createSessionMessageTransaction(
- mHubInterface, sessionId, halMessage, mPackageName, callback);
- try {
- mTransactionManager.addTransaction(transaction);
- } catch (IllegalStateException e) {
- Log.e(
- TAG,
- "Unable to add a transaction in sendMessageToEndpoint "
- + "(session ID = "
- + sessionId
- + ")",
- e);
- transaction.onTransactionComplete(
- ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE);
+ if (!info.isActive()) {
+ throw new SecurityException(
+ "sendMessage called on inactive session (id= " + sessionId + ")");
+ }
+
+ Message halMessage = ContextHubServiceUtil.createHalMessage(message);
+ if (callback == null) {
+ try {
+ mHubInterface.sendMessageToEndpoint(sessionId, halMessage);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Exception while sending message on session " + sessionId, e);
+ }
+ } else {
+ ContextHubServiceTransaction transaction =
+ mTransactionManager.createSessionMessageTransaction(
+ mHubInterface, sessionId, halMessage, mPackageName, callback);
+ try {
+ mTransactionManager.addTransaction(transaction);
+ info.setReliableMessagePending(transaction.getMessageSequenceNumber());
+ } catch (IllegalStateException e) {
+ Log.e(
+ TAG,
+ "Unable to add a transaction in sendMessageToEndpoint "
+ + "(session ID = "
+ + sessionId
+ + ")",
+ e);
+ transaction.onTransactionComplete(
+ ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE);
+ }
}
}
}
@@ -393,7 +424,9 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
int id = mSessionInfoMap.keyAt(i);
int count = i + 1;
sb.append(
- " " + count + ". id="
+ " "
+ + count
+ + ". id="
+ id
+ ", remote:"
+ mSessionInfoMap.get(id).getRemoteEndpointInfo());
@@ -461,13 +494,24 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
/* package */ void onMessageReceived(int sessionId, HubMessage message) {
byte code = onMessageReceivedInternal(sessionId, message);
if (code != ErrorCode.OK && message.isResponseRequired()) {
- sendMessageDeliveryStatus(
- sessionId, message.getMessageSequenceNumber(), code);
+ sendMessageDeliveryStatus(sessionId, message.getMessageSequenceNumber(), code);
}
}
/* package */ void onMessageDeliveryStatusReceived(
int sessionId, int sequenceNumber, byte errorCode) {
+ synchronized (mOpenSessionLock) {
+ SessionInfo info = mSessionInfoMap.get(sessionId);
+ if (info == null || !info.isActive()) {
+ Log.w(TAG, "Received delivery status for invalid session: id=" + sessionId);
+ return;
+ }
+ if (!info.isReliableMessagePending(sequenceNumber)) {
+ Log.w(TAG, "Received delivery status for unknown seq: " + sequenceNumber);
+ return;
+ }
+ info.setReliableMessageCompleted(sequenceNumber);
+ }
mTransactionManager.onMessageDeliveryResponse(sequenceNumber, errorCode == ErrorCode.OK);
}
@@ -492,7 +536,6 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
onCloseEndpointSession(id, Reason.HUB_RESET);
}
}
- // TODO(b/390029594): Cancel any ongoing reliable communication transactions
}
private Optional<Byte> onEndpointSessionOpenRequestInternal(
@@ -515,9 +558,11 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
mSessionInfoMap.put(sessionId, new SessionInfo(initiator, true));
}
- boolean success = invokeCallback(
- (consumer) ->
- consumer.onSessionOpenRequest(sessionId, initiator, serviceDescriptor));
+ boolean success =
+ invokeCallback(
+ (consumer) ->
+ consumer.onSessionOpenRequest(
+ sessionId, initiator, serviceDescriptor));
return success ? Optional.empty() : Optional.of(Reason.UNSPECIFIED);
}
@@ -590,8 +635,15 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
private boolean cleanupSessionResources(int sessionId) {
synchronized (mOpenSessionLock) {
SessionInfo info = mSessionInfoMap.get(sessionId);
- if (info != null && !info.isRemoteInitiated()) {
- mEndpointManager.returnSessionId(sessionId);
+ if (info != null) {
+ if (!info.isRemoteInitiated()) {
+ mEndpointManager.returnSessionId(sessionId);
+ }
+ info.forEachPendingReliableMessage(
+ (sequenceNumber) -> {
+ mTransactionManager.onMessageDeliveryResponse(
+ sequenceNumber, /* success= */ false);
+ });
mSessionInfoMap.remove(sessionId);
}
return info != null;
@@ -646,10 +698,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
try {
mWakeLock.release();
} catch (RuntimeException e) {
- Log.e(
- TAG,
- "Releasing the wakelock for all acquisitions fails - ",
- e);
+ Log.e(TAG, "Releasing the wakelock for all acquisitions fails - ", e);
break;
}
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index a430a82fc13b..6a1db0223db5 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -29,6 +29,7 @@ import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.time.Duration;
import java.util.ArrayDeque;
@@ -165,52 +166,61 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Creates a transaction for loading a nanoapp.
*
- * @param contextHubId the ID of the hub to load the nanoapp to
- * @param nanoAppBinary the binary of the nanoapp to load
+ * @param contextHubId the ID of the hub to load the nanoapp to
+ * @param nanoAppBinary the binary of the nanoapp to load
* @param onCompleteCallback the client on complete callback
* @return the generated transaction
*/
/* package */ ContextHubServiceTransaction createLoadTransaction(
- int contextHubId, NanoAppBinary nanoAppBinary,
- IContextHubTransactionCallback onCompleteCallback, String packageName) {
+ int contextHubId,
+ NanoAppBinary nanoAppBinary,
+ IContextHubTransactionCallback onCompleteCallback,
+ String packageName) {
return new ContextHubServiceTransaction(
- mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_LOAD_NANOAPP,
- nanoAppBinary.getNanoAppId(), packageName) {
+ mNextAvailableId.getAndIncrement(),
+ ContextHubTransaction.TYPE_LOAD_NANOAPP,
+ nanoAppBinary.getNanoAppId(),
+ packageName) {
@Override
- /* package */ int onTransact() {
+ /* package */ int onTransact() {
try {
return mContextHubProxy.loadNanoapp(
contextHubId, nanoAppBinary, this.getTransactionId());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while trying to load nanoapp with ID 0x" +
- Long.toHexString(nanoAppBinary.getNanoAppId()), e);
+ Log.e(
+ TAG,
+ "RemoteException while trying to load nanoapp with ID 0x"
+ + Long.toHexString(nanoAppBinary.getNanoAppId()),
+ e);
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
}
}
@Override
- /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
ContextHubStatsLog.write(
ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED,
nanoAppBinary.getNanoAppId(),
nanoAppBinary.getNanoAppVersion(),
ContextHubStatsLog
- .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_LOAD,
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_LOAD,
toStatsTransactionResult(result));
- ContextHubEventLogger.getInstance().logNanoappLoad(
- contextHubId,
- nanoAppBinary.getNanoAppId(),
- nanoAppBinary.getNanoAppVersion(),
- nanoAppBinary.getBinary().length,
- result == ContextHubTransaction.RESULT_SUCCESS);
+ ContextHubEventLogger.getInstance()
+ .logNanoappLoad(
+ contextHubId,
+ nanoAppBinary.getNanoAppId(),
+ nanoAppBinary.getNanoAppVersion(),
+ nanoAppBinary.getBinary().length,
+ result == ContextHubTransaction.RESULT_SUCCESS);
if (result == ContextHubTransaction.RESULT_SUCCESS) {
// 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.
mNanoAppStateManager.addNanoAppInstance(
- contextHubId, nanoAppBinary.getNanoAppId(),
+ contextHubId,
+ nanoAppBinary.getNanoAppId(),
nanoAppBinary.getNanoAppVersion());
}
try {
@@ -228,42 +238,51 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Creates a transaction for unloading a nanoapp.
*
- * @param contextHubId the ID of the hub to unload the nanoapp from
- * @param nanoAppId the ID of the nanoapp to unload
+ * @param contextHubId the ID of the hub to unload the nanoapp from
+ * @param nanoAppId the ID of the nanoapp to unload
* @param onCompleteCallback the client on complete callback
* @return the generated transaction
*/
/* package */ ContextHubServiceTransaction createUnloadTransaction(
- int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback,
+ int contextHubId,
+ long nanoAppId,
+ IContextHubTransactionCallback onCompleteCallback,
String packageName) {
return new ContextHubServiceTransaction(
- mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_UNLOAD_NANOAPP,
- nanoAppId, packageName) {
+ mNextAvailableId.getAndIncrement(),
+ ContextHubTransaction.TYPE_UNLOAD_NANOAPP,
+ nanoAppId,
+ packageName) {
@Override
- /* package */ int onTransact() {
+ /* package */ int onTransact() {
try {
return mContextHubProxy.unloadNanoapp(
contextHubId, nanoAppId, this.getTransactionId());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while trying to unload nanoapp with ID 0x" +
- Long.toHexString(nanoAppId), e);
+ Log.e(
+ TAG,
+ "RemoteException while trying to unload nanoapp with ID 0x"
+ + Long.toHexString(nanoAppId),
+ e);
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
}
}
@Override
- /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
ContextHubStatsLog.write(
- ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED, nanoAppId,
+ ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED,
+ nanoAppId,
0 /* nanoappVersion */,
ContextHubStatsLog
- .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_UNLOAD,
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_UNLOAD,
toStatsTransactionResult(result));
- ContextHubEventLogger.getInstance().logNanoappUnload(
- contextHubId,
- nanoAppId,
- result == ContextHubTransaction.RESULT_SUCCESS);
+ ContextHubEventLogger.getInstance()
+ .logNanoappUnload(
+ contextHubId,
+ nanoAppId,
+ result == ContextHubTransaction.RESULT_SUCCESS);
if (result == ContextHubTransaction.RESULT_SUCCESS) {
mNanoAppStateManager.removeNanoAppInstance(contextHubId, nanoAppId);
@@ -283,31 +302,37 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Creates a transaction for enabling a nanoapp.
*
- * @param contextHubId the ID of the hub to enable the nanoapp on
- * @param nanoAppId the ID of the nanoapp to enable
+ * @param contextHubId the ID of the hub to enable the nanoapp on
+ * @param nanoAppId the ID of the nanoapp to enable
* @param onCompleteCallback the client on complete callback
* @return the generated transaction
*/
/* package */ ContextHubServiceTransaction createEnableTransaction(
- int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback,
+ int contextHubId,
+ long nanoAppId,
+ IContextHubTransactionCallback onCompleteCallback,
String packageName) {
return new ContextHubServiceTransaction(
- mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_ENABLE_NANOAPP,
+ mNextAvailableId.getAndIncrement(),
+ ContextHubTransaction.TYPE_ENABLE_NANOAPP,
packageName) {
@Override
- /* package */ int onTransact() {
+ /* package */ int onTransact() {
try {
return mContextHubProxy.enableNanoapp(
contextHubId, nanoAppId, this.getTransactionId());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while trying to enable nanoapp with ID 0x" +
- Long.toHexString(nanoAppId), e);
+ Log.e(
+ TAG,
+ "RemoteException while trying to enable nanoapp with ID 0x"
+ + Long.toHexString(nanoAppId),
+ e);
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
}
}
@Override
- /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
try {
onCompleteCallback.onTransactionComplete(result);
} catch (RemoteException e) {
@@ -320,31 +345,37 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Creates a transaction for disabling a nanoapp.
*
- * @param contextHubId the ID of the hub to disable the nanoapp on
- * @param nanoAppId the ID of the nanoapp to disable
+ * @param contextHubId the ID of the hub to disable the nanoapp on
+ * @param nanoAppId the ID of the nanoapp to disable
* @param onCompleteCallback the client on complete callback
* @return the generated transaction
*/
/* package */ ContextHubServiceTransaction createDisableTransaction(
- int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback,
+ int contextHubId,
+ long nanoAppId,
+ IContextHubTransactionCallback onCompleteCallback,
String packageName) {
return new ContextHubServiceTransaction(
- mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_DISABLE_NANOAPP,
+ mNextAvailableId.getAndIncrement(),
+ ContextHubTransaction.TYPE_DISABLE_NANOAPP,
packageName) {
@Override
- /* package */ int onTransact() {
+ /* package */ int onTransact() {
try {
return mContextHubProxy.disableNanoapp(
contextHubId, nanoAppId, this.getTransactionId());
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while trying to disable nanoapp with ID 0x" +
- Long.toHexString(nanoAppId), e);
+ Log.e(
+ TAG,
+ "RemoteException while trying to disable nanoapp with ID 0x"
+ + Long.toHexString(nanoAppId),
+ e);
return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
}
}
@Override
- /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
try {
onCompleteCallback.onTransactionComplete(result);
} catch (RemoteException e) {
@@ -447,18 +478,20 @@ import java.util.concurrent.atomic.AtomicInteger;
/**
* Creates a transaction for querying for a list of nanoapps.
*
- * @param contextHubId the ID of the hub to query
+ * @param contextHubId the ID of the hub to query
* @param onCompleteCallback the client on complete callback
* @return the generated transaction
*/
/* package */ ContextHubServiceTransaction createQueryTransaction(
- int contextHubId, IContextHubTransactionCallback onCompleteCallback,
+ int contextHubId,
+ IContextHubTransactionCallback onCompleteCallback,
String packageName) {
return new ContextHubServiceTransaction(
- mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_QUERY_NANOAPPS,
+ mNextAvailableId.getAndIncrement(),
+ ContextHubTransaction.TYPE_QUERY_NANOAPPS,
packageName) {
@Override
- /* package */ int onTransact() {
+ /* package */ int onTransact() {
try {
return mContextHubProxy.queryNanoapps(contextHubId);
} catch (RemoteException e) {
@@ -468,12 +501,12 @@ import java.util.concurrent.atomic.AtomicInteger;
}
@Override
- /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
+ /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) {
onQueryResponse(result, Collections.emptyList());
}
@Override
- /* package */ void onQueryResponse(
+ /* package */ void onQueryResponse(
@ContextHubTransaction.Result int result, List<NanoAppState> nanoAppStateList) {
try {
onCompleteCallback.onQueryResponse(result, nanoAppStateList);
@@ -539,6 +572,14 @@ import java.util.concurrent.atomic.AtomicInteger;
}
}
+ @VisibleForTesting
+ /* package */
+ int numReliableMessageTransactionPending() {
+ synchronized (mReliableMessageLock) {
+ return mReliableMessageTransactionMap.size();
+ }
+ }
+
/**
* Handles a transaction response from a Context Hub.
*
@@ -585,18 +626,21 @@ import java.util.concurrent.atomic.AtomicInteger;
void onMessageDeliveryResponse(int messageSequenceNumber, boolean success) {
if (!Flags.reliableMessageRetrySupportService()) {
TransactionAcceptConditions conditions =
- transaction -> transaction.getTransactionType()
- == ContextHubTransaction.TYPE_RELIABLE_MESSAGE
- && transaction.getMessageSequenceNumber()
- == messageSequenceNumber;
+ transaction ->
+ transaction.getTransactionType()
+ == ContextHubTransaction.TYPE_RELIABLE_MESSAGE
+ && transaction.getMessageSequenceNumber()
+ == messageSequenceNumber;
ContextHubServiceTransaction transaction = getTransactionAndHandleNext(conditions);
if (transaction == null) {
- Log.w(TAG, "Received unexpected message delivery response (expected"
- + " message sequence number = "
- + messageSequenceNumber
- + ", received messageSequenceNumber = "
- + messageSequenceNumber
- + ")");
+ Log.w(
+ TAG,
+ "Received unexpected message delivery response (expected"
+ + " message sequence number = "
+ + messageSequenceNumber
+ + ", received messageSequenceNumber = "
+ + messageSequenceNumber
+ + ")");
return;
}
@@ -640,8 +684,10 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
/* package */
void onQueryResponse(List<NanoAppState> nanoAppStateList) {
- TransactionAcceptConditions conditions = transaction ->
- transaction.getTransactionType() == ContextHubTransaction.TYPE_QUERY_NANOAPPS;
+ TransactionAcceptConditions conditions =
+ transaction ->
+ transaction.getTransactionType()
+ == ContextHubTransaction.TYPE_QUERY_NANOAPPS;
ContextHubServiceTransaction transaction = getTransactionAndHandleNext(conditions);
if (transaction == null) {
Log.w(TAG, "Received unexpected query response");
@@ -968,24 +1014,33 @@ import java.util.concurrent.atomic.AtomicInteger;
private int toStatsTransactionResult(@ContextHubTransaction.Result int result) {
switch (result) {
case ContextHubTransaction.RESULT_SUCCESS:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_SUCCESS;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_SUCCESS;
case ContextHubTransaction.RESULT_FAILED_BAD_PARAMS:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BAD_PARAMS;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BAD_PARAMS;
case ContextHubTransaction.RESULT_FAILED_UNINITIALIZED:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNINITIALIZED;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNINITIALIZED;
case ContextHubTransaction.RESULT_FAILED_BUSY:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BUSY;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_BUSY;
case ContextHubTransaction.RESULT_FAILED_AT_HUB:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_AT_HUB;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_AT_HUB;
case ContextHubTransaction.RESULT_FAILED_TIMEOUT:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_TIMEOUT;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_TIMEOUT;
case ContextHubTransaction.RESULT_FAILED_SERVICE_INTERNAL_FAILURE:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_SERVICE_INTERNAL_FAILURE;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_SERVICE_INTERNAL_FAILURE;
case ContextHubTransaction.RESULT_FAILED_HAL_UNAVAILABLE:
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_HAL_UNAVAILABLE;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_HAL_UNAVAILABLE;
case ContextHubTransaction.RESULT_FAILED_UNKNOWN:
default: /* fall through */
- return ContextHubStatsLog.CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNKNOWN;
+ return ContextHubStatsLog
+ .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_RESULT__TRANSACTION_RESULT_FAILED_UNKNOWN;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
index a4e77c00d647..1de864cb4eb0 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
@@ -17,9 +17,9 @@
package com.android.server.location.contexthub;
import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,15 +33,21 @@ import android.hardware.contexthub.HubMessage;
import android.hardware.contexthub.IContextHubEndpoint;
import android.hardware.contexthub.IContextHubEndpointCallback;
import android.hardware.contexthub.IEndpointCommunication;
+import android.hardware.contexthub.Message;
import android.hardware.contexthub.MessageDeliveryStatus;
import android.hardware.contexthub.Reason;
+import android.hardware.location.IContextHubTransactionCallback;
+import android.hardware.location.NanoAppState;
import android.os.Binder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
-
+import android.util.Log;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
+import java.util.Collections;
+import java.util.List;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -51,11 +57,11 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.Collections;
-
@RunWith(AndroidJUnit4.class)
@Presubmit
public class ContextHubEndpointTest {
+ private static final String TAG = "ContextHubEndpointTest";
+
private static final int SESSION_ID_RANGE = ContextHubEndpointManager.SERVICE_SESSION_RANGE;
private static final int MIN_SESSION_ID = 0;
private static final int MAX_SESSION_ID = MIN_SESSION_ID + SESSION_ID_RANGE - 1;
@@ -206,6 +212,68 @@ public class ContextHubEndpointTest {
assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE);
}
+ @Test
+ public void testMessageTransaction() throws RemoteException {
+ IContextHubEndpoint endpoint = registerExampleEndpoint();
+ testMessageTransactionInternal(endpoint, /* deliverMessageStatus= */ true);
+
+ unregisterExampleEndpoint(endpoint);
+ }
+
+ @Test
+ public void testMessageTransactionCleanupOnUnregistration() throws RemoteException {
+ IContextHubEndpoint endpoint = registerExampleEndpoint();
+ testMessageTransactionInternal(endpoint, /* deliverMessageStatus= */ false);
+
+ unregisterExampleEndpoint(endpoint);
+ assertThat(mTransactionManager.numReliableMessageTransactionPending()).isEqualTo(0);
+ }
+
+ /** A helper method to create a session and validates reliable message sending. */
+ private void testMessageTransactionInternal(
+ IContextHubEndpoint endpoint, boolean deliverMessageStatus) throws RemoteException {
+ HubEndpointInfo targetInfo =
+ new HubEndpointInfo(
+ TARGET_ENDPOINT_NAME,
+ TARGET_ENDPOINT_ID,
+ ENDPOINT_PACKAGE_NAME,
+ Collections.emptyList());
+ int sessionId = endpoint.openSession(targetInfo, /* serviceDescriptor= */ null);
+ mEndpointManager.onEndpointSessionOpenComplete(sessionId);
+
+ final int messageType = 1234;
+ HubMessage message =
+ new HubMessage.Builder(messageType, new byte[] {1, 2, 3, 4, 5})
+ .setResponseRequired(true)
+ .build();
+ IContextHubTransactionCallback callback =
+ new IContextHubTransactionCallback.Stub() {
+ @Override
+ public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+ Log.i(TAG, "Received onQueryResponse callback, result=" + result);
+ }
+
+ @Override
+ public void onTransactionComplete(int result) {
+ Log.i(TAG, "Received onTransactionComplete callback, result=" + result);
+ }
+ };
+ endpoint.sendMessage(sessionId, message, callback);
+ ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mMockEndpointCommunications, timeout(1000))
+ .sendMessageToEndpoint(eq(sessionId), messageCaptor.capture());
+ Message halMessage = messageCaptor.getValue();
+ assertThat(halMessage.type).isEqualTo(message.getMessageType());
+ assertThat(halMessage.content).isEqualTo(message.getMessageBody());
+ assertThat(mTransactionManager.numReliableMessageTransactionPending()).isEqualTo(1);
+
+ if (deliverMessageStatus) {
+ mEndpointManager.onMessageDeliveryStatusReceived(
+ sessionId, halMessage.sequenceNumber, ErrorCode.OK);
+ assertThat(mTransactionManager.numReliableMessageTransactionPending()).isEqualTo(0);
+ }
+ }
+
private IContextHubEndpoint registerExampleEndpoint() throws RemoteException {
HubEndpointInfo info =
new HubEndpointInfo(