From 672d8a7ab9be747acf21680ad89ba77340238268 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Mon, 2 Dec 2019 15:16:08 -0800 Subject: [PATCH] Adds client info in ContextHubService dump Example: ... =================== CLIENTS ==================== [ContextHubClient endpointID: 0, contextHub: 0, package: android.uid.system:1000] [ContextHubClient endpointID: 1, contextHub: 0, package: com.google.oslo] [ContextHubClient endpointID: 2, contextHub: 0, package: com.google.oslo] [ContextHubClient endpointID: 3, contextHub: 0, package: com.google.oslo] [ContextHubClient endpointID: 4, contextHub: 0, package: com.google.oslo] [ContextHubClient endpointID: 5, contextHub: 0, package: com.google.oslo] [ContextHubClient endpointID: 6, contextHub: 0, package: com.google.oslo] [ContextHubClient endpointID: 7, contextHub: 0, package: android.uid.systemui:10124] [ContextHubClient endpointID: 8, contextHub: 0, intentCreatorPackage: com.google.android.apps.scone, nanoAppId: 0x476f6f676c001016] Registration history: 12/03 14:58:17.410 - [ContextHubClient endpointID: 9, contextHub: 0, package: com.google.uid.shared:10113] 12/03 14:58:17.403 + [ContextHubClient endpointID: 9, contextHub: 0, package: com.google.uid.shared:10113] 12/03 14:58:10.295 + [ContextHubClient endpointID: 8, contextHub: 0, intentCreatorPackage: com.google.android.apps.scone, nanoAppId: 0x476f6f676c001016] 12/03 14:58:05.501 + [ContextHubClient endpointID: 7, contextHub: 0, package: android.uid.systemui:10124] 12/03 14:58:05.379 + [ContextHubClient endpointID: 6, contextHub: 0, package: com.google.oslo] 12/03 14:58:05.375 + [ContextHubClient endpointID: 5, contextHub: 0, package: com.google.oslo] 12/03 14:58:05.371 + [ContextHubClient endpointID: 4, contextHub: 0, package: com.google.oslo] 12/03 14:58:05.367 + [ContextHubClient endpointID: 3, contextHub: 0, package: com.google.oslo] 12/03 14:58:05.365 + [ContextHubClient endpointID: 2, contextHub: 0, package: com.google.oslo] 12/03 14:58:05.362 + [ContextHubClient endpointID: 1, contextHub: 0, package: com.google.oslo] 12/03 14:58:04.257 + [ContextHubClient endpointID: 0, contextHub: 0, package: android.uid.system:1000] Bug: 121033022 Test: adb shell dumpsys contexthub Change-Id: I33f49c1e8a144ea2818add0e0b4c52d1f5454b65 --- .../location/ContextHubClientBroker.java | 45 ++++++++ .../location/ContextHubClientManager.java | 106 ++++++++++++++++++ .../server/location/ContextHubService.java | 4 + 3 files changed, 155 insertions(+) diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java index 675e59e8f9609..45d9bae23e268 100644 --- a/services/core/java/com/android/server/location/ContextHubClientBroker.java +++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java @@ -29,10 +29,12 @@ import android.hardware.location.ContextHubTransaction; import android.hardware.location.IContextHubClient; import android.hardware.location.IContextHubClientCallback; import android.hardware.location.NanoAppMessage; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; /** @@ -96,6 +98,16 @@ public class ContextHubClientBroker extends IContextHubClient.Stub */ private final PendingIntentRequest mPendingIntentRequest; + /* + * The host package associated with this client. + */ + private final String mPackage; + + /* + * True if a PendingIntent has been cancelled. + */ + private AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false); + /* * Helper class to manage registered PendingIntent requests from the client. */ @@ -110,11 +122,14 @@ public class ContextHubClientBroker extends IContextHubClient.Stub */ private long mNanoAppId; + private boolean mValid = false; + PendingIntentRequest() {} PendingIntentRequest(PendingIntent pendingIntent, long nanoAppId) { mPendingIntent = pendingIntent; mNanoAppId = nanoAppId; + mValid = true; } public long getNanoAppId() { @@ -132,6 +147,10 @@ public class ContextHubClientBroker extends IContextHubClient.Stub public void clear() { mPendingIntent = null; } + + public boolean isValid() { + return mValid; + } } /* package */ ContextHubClientBroker( @@ -145,6 +164,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub mHostEndPointId = hostEndPointId; mCallbackInterface = callback; mPendingIntentRequest = new PendingIntentRequest(); + mPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid()); } /* package */ ContextHubClientBroker( @@ -157,6 +177,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub mAttachedContextHubInfo = contextHubInfo; mHostEndPointId = hostEndPointId; mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId); + mPackage = pendingIntent.getCreatorPackage(); } /** @@ -312,6 +333,13 @@ public class ContextHubClientBroker extends IContextHubClient.Stub } } + /** + * @return true if the client is a PendingIntent client that has been cancelled. + */ + /* package */ boolean isPendingIntentCancelled() { + return mIsPendingIntentCancelled.get(); + } + /** * Helper function to invoke a specified client callback, if the connection is open. * @@ -392,6 +420,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub Manifest.permission.LOCATION_HARDWARE /* requiredPermission */, null /* options */); } catch (PendingIntent.CanceledException e) { + mIsPendingIntentCancelled.set(true); // The PendingIntent is no longer valid Log.w(TAG, "PendingIntent has been canceled, unregistering from client" + " (host endpoint ID " + mHostEndPointId + ")"); @@ -419,4 +448,20 @@ public class ContextHubClientBroker extends IContextHubClient.Stub mRegistered = false; } } + + @Override + public String toString() { + String out = "[ContextHubClient "; + out += "endpointID: " + getHostEndPointId() + ", "; + out += "contextHub: " + getAttachedContextHubId() + ", "; + if (mPendingIntentRequest.isValid()) { + out += "intentCreatorPackage: " + mPackage + ", "; + out += "nanoAppId: 0x" + Long.toHexString(mPendingIntentRequest.getNanoAppId()); + } else { + out += "package: " + mPackage; + } + out += "]"; + + return out; + } } diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java index 00b7d62738c09..46db8dc5dd77f 100644 --- a/services/core/java/com/android/server/location/ContextHubClientManager.java +++ b/services/core/java/com/android/server/location/ContextHubClientManager.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.annotation.IntDef; import android.app.PendingIntent; import android.content.Context; import android.hardware.contexthub.V1_0.ContextHubMsg; @@ -27,7 +28,12 @@ import android.hardware.location.NanoAppMessage; import android.os.RemoteException; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Calendar; +import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.function.Consumer; /** @@ -71,6 +77,79 @@ import java.util.function.Consumer; */ private int mNextHostEndPointId = 0; + /* + * The list of previous registration records. + */ + private static final int NUM_CLIENT_RECORDS = 20; + private final ConcurrentLinkedEvictingDeque mRegistrationRecordDeque = + new ConcurrentLinkedEvictingDeque<>(NUM_CLIENT_RECORDS); + + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ACTION_" }, value = { + ACTION_REGISTERED, + ACTION_UNREGISTERED, + ACTION_CANCELLED, + }) + public @interface Action {} + public static final int ACTION_REGISTERED = 0; + public static final int ACTION_UNREGISTERED = 1; + public static final int ACTION_CANCELLED = 2; + + /** + * Helper class to make a ConcurrentLinkedDeque fixed-size, evicting old entries when full. + */ + private class ConcurrentLinkedEvictingDeque extends ConcurrentLinkedDeque { + private int mSize; + + ConcurrentLinkedEvictingDeque(int size) { + mSize = size; + } + + @Override + public boolean add(E elem) { + synchronized (this) { + if (size() == mSize) { + poll(); + } + + return super.add(elem); + } + } + } + + /** + * A container class to store a record of ContextHubClient registration. + */ + private class RegistrationRecord { + private final String mBroker; + private final int mAction; + private final String mDate; + + RegistrationRecord(String broker, @Action int action) { + mBroker = broker; + mAction = action; + Calendar instance = Calendar.getInstance(); + mDate = String.format("%02d", instance.get(Calendar.MONTH) + 1) // Jan == 0 + + "/" + String.format("%02d", instance.get(Calendar.DAY_OF_MONTH)) + + " " + String.format("%02d", instance.get(Calendar.HOUR_OF_DAY)) + + ":" + String.format("%02d", instance.get(Calendar.MINUTE)) + + ":" + String.format("%02d", instance.get(Calendar.SECOND)) + + "." + String.format("%03d", instance.get(Calendar.MILLISECOND)); + } + + @Override + public String toString() { + String out = ""; + out += mDate + " "; + out += mAction == ACTION_REGISTERED ? "+ " : "- "; + out += mBroker; + if (mAction == ACTION_CANCELLED) { + out += " (cancelled)"; + } + return out; + } + } + /* package */ ContextHubClientManager( Context context, IContexthub contextHubProxy) { mContext = context; @@ -96,6 +175,8 @@ import java.util.function.Consumer; mContext, mContextHubProxy, this /* clientManager */, contextHubInfo, hostEndPointId, clientCallback); mHostEndPointIdToClientMap.put(hostEndPointId, broker); + mRegistrationRecordDeque.add( + new RegistrationRecord(broker.toString(), ACTION_REGISTERED)); } try { @@ -136,6 +217,8 @@ import java.util.function.Consumer; hostEndPointId, pendingIntent, nanoAppId); mHostEndPointIdToClientMap.put(hostEndPointId, broker); registerString = "Registered"; + mRegistrationRecordDeque.add( + new RegistrationRecord(broker.toString(), ACTION_REGISTERED)); } } @@ -178,6 +261,13 @@ import java.util.function.Consumer; * @param hostEndPointId the host endpoint ID of the client that has died */ /* package */ void unregisterClient(short hostEndPointId) { + ContextHubClientBroker broker = mHostEndPointIdToClientMap.get(hostEndPointId); + if (broker != null) { + @Action int action = + broker.isPendingIntentCancelled() ? ACTION_CANCELLED : ACTION_UNREGISTERED; + mRegistrationRecordDeque.add(new RegistrationRecord(broker.toString(), action)); + } + if (mHostEndPointIdToClientMap.remove(hostEndPointId) != null) { Log.d(TAG, "Unregistered client with host endpoint ID " + hostEndPointId); } else { @@ -285,4 +375,20 @@ import java.util.function.Consumer; return null; } + + @Override + public String toString() { + String out = ""; + for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) { + out += broker + "\n"; + } + + out += "\nRegistration history:\n"; + Iterator it = mRegistrationRecordDeque.descendingIterator(); + while (it.hasNext()) { + out += it.next() + "\n"; + } + + return out; + } } diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java index 36b0342c21d83..787a8007920d3 100644 --- a/services/core/java/com/android/server/location/ContextHubService.java +++ b/services/core/java/com/android/server/location/ContextHubService.java @@ -795,6 +795,10 @@ public class ContextHubService extends IContextHubService.Stub { // Dump nanoAppHash mNanoAppStateManager.foreachNanoAppInstanceInfo((info) -> pw.println(info)); + pw.println(""); + pw.println("=================== CLIENTS ===================="); + pw.println(mClientManager); + // dump eventLog }