diff --git a/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java b/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java new file mode 100644 index 0000000000000..6910c353e546f --- /dev/null +++ b/services/core/java/com/android/server/location/ConcurrentLinkedEvictingDeque.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020 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 java.util.concurrent.ConcurrentLinkedDeque; + +/** + * Helper class to make a ConcurrentLinkedDeque fixed-size, evicting old entries when full. + * + * @param The type of elements held in this queue. + */ +public 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); + } + } +} diff --git a/services/core/java/com/android/server/location/ContextHubClientManager.java b/services/core/java/com/android/server/location/ContextHubClientManager.java index 0f70bb8bc840f..33ceeeff331f2 100644 --- a/services/core/java/com/android/server/location/ContextHubClientManager.java +++ b/services/core/java/com/android/server/location/ContextHubClientManager.java @@ -36,7 +36,6 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedDeque; import java.util.function.Consumer; /** @@ -103,28 +102,6 @@ import java.util.function.Consumer; 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. */ diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java index 48b22704fd073..264c611d45fe7 100644 --- a/services/core/java/com/android/server/location/ContextHubService.java +++ b/services/core/java/com/android/server/location/ContextHubService.java @@ -43,6 +43,7 @@ import android.hardware.location.NanoAppInstanceInfo; import android.hardware.location.NanoAppMessage; import android.hardware.location.NanoAppState; import android.location.LocationManager; +import android.os.Binder; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; @@ -386,7 +387,7 @@ public class ContextHubService extends IContextHubService.Stub { createLoadTransactionCallback(contextHubHandle, nanoAppBinary); ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction( - contextHubHandle, nanoAppBinary, onCompleteCallback); + contextHubHandle, nanoAppBinary, onCompleteCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); return 0; @@ -411,7 +412,7 @@ public class ContextHubService extends IContextHubService.Stub { IContextHubTransactionCallback onCompleteCallback = createUnloadTransactionCallback(contextHubId); ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction( - contextHubId, nanoAppId, onCompleteCallback); + contextHubId, nanoAppId, onCompleteCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); return 0; @@ -464,7 +465,7 @@ public class ContextHubService extends IContextHubService.Stub { IContextHubTransactionCallback onCompleteCallback = createQueryTransactionCallback(contextHubId); ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( - contextHubId, onCompleteCallback); + contextHubId, onCompleteCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); return Result.OK; @@ -696,7 +697,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction( - contextHubId, nanoAppBinary, transactionCallback); + contextHubId, nanoAppBinary, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -720,7 +721,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction( - contextHubId, nanoAppId, transactionCallback); + contextHubId, nanoAppId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -744,7 +745,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createEnableTransaction( - contextHubId, nanoAppId, transactionCallback); + contextHubId, nanoAppId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -768,7 +769,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createDisableTransaction( - contextHubId, nanoAppId, transactionCallback); + contextHubId, nanoAppId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -790,7 +791,7 @@ public class ContextHubService extends IContextHubService.Stub { } ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction( - contextHubId, transactionCallback); + contextHubId, transactionCallback, getCallingPackageName()); mTransactionManager.addTransaction(transaction); } @@ -822,6 +823,10 @@ public class ContextHubService extends IContextHubService.Stub { pw.println("=================== CLIENTS ===================="); pw.println(mClientManager); + pw.println(""); + pw.println("=================== TRANSACTIONS ===================="); + pw.println(mTransactionManager); + // dump eventLog } @@ -924,4 +929,8 @@ public class ContextHubService extends IContextHubService.Stub { mContextHubWrapper.onSettingChanged(Setting.LOCATION, enabled ? SettingValue.ENABLED : SettingValue.DISABLED); } + + private String getCallingPackageName() { + return mContext.getPackageManager().getNameForUid(Binder.getCallingUid()); + } } diff --git a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java index c1fc98248e08f..62bd91bda1b8a 100644 --- a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java +++ b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java @@ -32,14 +32,32 @@ import java.util.concurrent.TimeUnit; @ContextHubTransaction.Type private final int mTransactionType; + /* The ID of the nanoapp this transaction is targeted for, null if not applicable. */ + private final Long mNanoAppId; + + /* + * The host package associated with this transaction. + */ + private final String mPackage; + /* * true if the transaction has already completed, false otherwise */ private boolean mIsComplete = false; - /* package */ ContextHubServiceTransaction(int id, int type) { + /* package */ ContextHubServiceTransaction(int id, int type, String packageName) { mTransactionId = id; mTransactionType = type; + mNanoAppId = null; + mPackage = packageName; + } + + /* package */ ContextHubServiceTransaction(int id, int type, long nanoAppId, + String packageName) { + mTransactionId = id; + mTransactionType = type; + mNanoAppId = nanoAppId; + mPackage = packageName; } /** @@ -129,7 +147,13 @@ import java.util.concurrent.TimeUnit; @Override public String toString() { - return ContextHubTransaction.typeToString(mTransactionType, true /* upperCase */) - + " transaction (ID = " + mTransactionId + ")"; + String out = ContextHubTransaction.typeToString(mTransactionType, true /* upperCase */) + + " ("; + if (mNanoAppId != null) { + out += "appId = 0x" + Long.toHexString(mNanoAppId) + ", "; + } + out += "package = " + mPackage + ")"; + + return out; } } diff --git a/services/core/java/com/android/server/location/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/ContextHubTransactionManager.java index cced781f8e1b5..d3fc7058bcf2e 100644 --- a/services/core/java/com/android/server/location/ContextHubTransactionManager.java +++ b/services/core/java/com/android/server/location/ContextHubTransactionManager.java @@ -26,11 +26,15 @@ import android.hardware.location.NanoAppState; import android.os.RemoteException; import android.util.Log; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayDeque; import java.util.Collections; +import java.util.Date; +import java.util.Iterator; import java.util.List; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -52,6 +56,11 @@ import java.util.concurrent.atomic.AtomicInteger; */ private static final int MAX_PENDING_REQUESTS = 10000; + /* + * The DateFormat for printing TransactionRecord. + */ + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd HH:mm:ss.SSS"); + /* * The proxy to talk to the Context Hub */ @@ -83,6 +92,33 @@ import java.util.concurrent.atomic.AtomicInteger; private final ScheduledThreadPoolExecutor mTimeoutExecutor = new ScheduledThreadPoolExecutor(1); private ScheduledFuture mTimeoutFuture = null; + /* + * The list of previous transaction records. + */ + private static final int NUM_TRANSACTION_RECORDS = 20; + private final ConcurrentLinkedEvictingDeque mTransactionRecordDeque = + new ConcurrentLinkedEvictingDeque<>(NUM_TRANSACTION_RECORDS); + + /** + * A container class to store a record of transactions. + */ + private class TransactionRecord { + private final String mTransaction; + private final long mTimestamp; + + TransactionRecord(String transaction) { + mTransaction = transaction; + mTimestamp = System.currentTimeMillis(); + } + + // TODO: Add dump to proto here + + @Override + public String toString() { + return DATE_FORMAT.format(new Date(mTimestamp)) + " " + mTransaction; + } + } + /* package */ ContextHubTransactionManager( IContexthub contextHubProxy, ContextHubClientManager clientManager, NanoAppStateManager nanoAppStateManager) { @@ -101,11 +137,12 @@ import java.util.concurrent.atomic.AtomicInteger; */ /* package */ ContextHubServiceTransaction createLoadTransaction( int contextHubId, NanoAppBinary nanoAppBinary, - IContextHubTransactionCallback onCompleteCallback) { + IContextHubTransactionCallback onCompleteCallback, String packageName) { return new ContextHubServiceTransaction( - mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_LOAD_NANOAPP) { + mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_LOAD_NANOAPP, + nanoAppBinary.getNanoAppId(), packageName) { @Override - /* package */ int onTransact() { + /* package */ int onTransact() { android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary = ContextHubServiceUtil.createHidlNanoAppBinary(nanoAppBinary); try { @@ -119,7 +156,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { 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 @@ -149,11 +186,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @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) { + mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_UNLOAD_NANOAPP, + nanoAppId, packageName) { @Override - /* package */ int onTransact() { + /* package */ int onTransact() { try { return mContextHubProxy.unloadNanoApp( contextHubId, nanoAppId, this.getTransactionId()); @@ -165,7 +204,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { if (result == ContextHubTransaction.RESULT_SUCCESS) { mNanoAppStateManager.removeNanoAppInstance(contextHubId, nanoAppId); } @@ -190,11 +229,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @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()); @@ -206,7 +247,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { try { onCompleteCallback.onTransactionComplete(result); } catch (RemoteException e) { @@ -225,11 +266,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @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()); @@ -241,7 +284,7 @@ import java.util.concurrent.atomic.AtomicInteger; } @Override - /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { + /* package */ void onTransactionComplete(@ContextHubTransaction.Result int result) { try { onCompleteCallback.onTransactionComplete(result); } catch (RemoteException e) { @@ -259,11 +302,13 @@ import java.util.concurrent.atomic.AtomicInteger; * @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.queryApps(contextHubId); } catch (RemoteException e) { @@ -273,12 +318,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 nanoAppStateList) { try { onCompleteCallback.onQueryResponse(result, nanoAppStateList); @@ -307,6 +352,7 @@ import java.util.concurrent.atomic.AtomicInteger; + MAX_PENDING_REQUESTS + ")"); } mTransactionQueue.add(transaction); + mTransactionRecordDeque.add(new TransactionRecord(transaction.toString())); if (mTransactionQueue.size() == 1) { startNextTransaction(); @@ -433,4 +479,23 @@ import java.util.concurrent.atomic.AtomicInteger; } } } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(100); + TransactionRecord[] arr; + synchronized (this) { + arr = mTransactionQueue.toArray(new TransactionRecord[0]); + } + for (int i = 0; i < arr.length; i++) { + sb.append(i + ": " + arr[i] + "\n"); + } + + sb.append("Transaction History:\n"); + Iterator iterator = mTransactionRecordDeque.descendingIterator(); + while (iterator.hasNext()) { + sb.append(iterator.next() + "\n"); + } + return sb.toString(); + } }