diff options
author | 2024-11-29 17:04:00 +0000 | |
---|---|---|
committer | 2024-12-09 13:17:54 +0000 | |
commit | 1670d281b339817d114f71cc927850504a973bf9 (patch) | |
tree | 7506004c4f8301ffc402162abbfa0d0e122487a2 | |
parent | e6378dbf40a5973771d3444f0235ca1d2fb71664 (diff) |
Log AppFunctionsRequestReported
Flag: android.app.appfunctions.flags.enable_app_function_manager
Bug: 376688078
Test: manual test
Change-Id: I9e4cdb9d517c6f953f08668d0c89373ffa6b6261
8 files changed, 159 insertions, 11 deletions
diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java index ed088fed41c2..a731e5085466 100644 --- a/core/java/android/app/appfunctions/AppFunctionManager.java +++ b/core/java/android/app/appfunctions/AppFunctionManager.java @@ -34,6 +34,7 @@ import android.os.ICancellationSignal; import android.os.OutcomeReceiver; import android.os.ParcelableException; import android.os.RemoteException; +import android.os.SystemClock; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -179,7 +180,8 @@ public final class AppFunctionManager { ExecuteAppFunctionAidlRequest aidlRequest = new ExecuteAppFunctionAidlRequest( - request, mContext.getUser(), mContext.getPackageName()); + request, mContext.getUser(), mContext.getPackageName(), + /* requestTime= */ SystemClock.elapsedRealtime()); try { ICancellationSignal cancellationTransport = diff --git a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java index e623fa10f474..707d1fc0473e 100644 --- a/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java +++ b/core/java/android/app/appfunctions/ExecuteAppFunctionAidlRequest.java @@ -41,8 +41,9 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { ExecuteAppFunctionRequest.CREATOR.createFromParcel(in); UserHandle userHandle = UserHandle.CREATOR.createFromParcel(in); String callingPackage = in.readString8(); + long requestTime = in.readLong(); return new ExecuteAppFunctionAidlRequest( - clientRequest, userHandle, callingPackage); + clientRequest, userHandle, callingPackage, requestTime); } @Override @@ -60,11 +61,15 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { /** The package name of the app that is requesting to execute the app function. */ private final String mCallingPackage; - public ExecuteAppFunctionAidlRequest( - ExecuteAppFunctionRequest clientRequest, UserHandle userHandle, String callingPackage) { + /** The time of calling executeAppFunction(). */ + private final long mRequestTime; + + public ExecuteAppFunctionAidlRequest(ExecuteAppFunctionRequest clientRequest, + UserHandle userHandle, String callingPackage, long requestTime) { this.mClientRequest = Objects.requireNonNull(clientRequest); this.mUserHandle = Objects.requireNonNull(userHandle); this.mCallingPackage = Objects.requireNonNull(callingPackage); + this.mRequestTime = requestTime; } @Override @@ -77,6 +82,7 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { mClientRequest.writeToParcel(dest, flags); mUserHandle.writeToParcel(dest, flags); dest.writeString8(mCallingPackage); + dest.writeLong(mRequestTime); } /** Returns the client request to execute an app function. */ @@ -96,4 +102,9 @@ public final class ExecuteAppFunctionAidlRequest implements Parcelable { public String getCallingPackage() { return mCallingPackage; } + + /** Returns the time of calling executeAppFunction(). */ + public long getRequestTime() { + return mRequestTime; + } } diff --git a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java index 2426daf5c9f2..e290169bdea8 100644 --- a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java +++ b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java @@ -17,6 +17,7 @@ package android.app.appfunctions; import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.RemoteException; import android.util.Log; @@ -37,8 +38,16 @@ public class SafeOneTimeExecuteAppFunctionCallback { @NonNull private final IExecuteAppFunctionCallback mCallback; + @Nullable CompletionCallback mCompletionCallback; + public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback) { + this(callback, /* completionCallback= */ null); + } + + public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback, + @Nullable CompletionCallback completionCallback) { mCallback = Objects.requireNonNull(callback); + mCompletionCallback = completionCallback; } /** Invoke wrapped callback with the result. */ @@ -49,6 +58,9 @@ public class SafeOneTimeExecuteAppFunctionCallback { } try { mCallback.onSuccess(result); + if (mCompletionCallback != null) { + mCompletionCallback.finalizeOnSuccess(result); + } } catch (RemoteException ex) { // Failed to notify the other end. Ignore. Log.w(TAG, "Failed to invoke the callback", ex); @@ -63,6 +75,9 @@ public class SafeOneTimeExecuteAppFunctionCallback { } try { mCallback.onError(error); + if (mCompletionCallback != null) { + mCompletionCallback.finalizeOnError(error); + } } catch (RemoteException ex) { // Failed to notify the other end. Ignore. Log.w(TAG, "Failed to invoke the callback", ex); @@ -76,4 +91,16 @@ public class SafeOneTimeExecuteAppFunctionCallback { public void disable() { mOnResultCalled.set(true); } + + /** + * Provides a hook to execute additional actions after the {@link IExecuteAppFunctionCallback} + * has been invoked. + */ + public interface CompletionCallback { + /** Called after {@link IExecuteAppFunctionCallback#onSuccess}. */ + void finalizeOnSuccess(@NonNull ExecuteAppFunctionResponse result); + + /** Called after {@link IExecuteAppFunctionCallback#onError}. */ + void finalizeOnError(@NonNull AppFunctionException error); + } } diff --git a/services/appfunctions/Android.bp b/services/appfunctions/Android.bp index eb6e46861898..7337aa26c145 100644 --- a/services/appfunctions/Android.bp +++ b/services/appfunctions/Android.bp @@ -19,6 +19,7 @@ java_library_static { defaults: ["platform_service_defaults"], srcs: [ ":services.appfunctions-sources", + ":statslog-appfunctions-java-gen", "java/**/*.logtags", ], libs: ["services.core"], @@ -26,3 +27,10 @@ java_library_static { baseline_filename: "lint-baseline.xml", }, } + +genrule { + name: "statslog-appfunctions-java-gen", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --java $(out) --module appfunctions --javaPackage com.android.server.appfunctions --javaClass AppFunctionsStatsLog --minApiLevel 35", + out: ["java/com/android/server/appfunctions/AppFunctionsStatsLog.java"], +} diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java index 81e83b563945..eaea4435099c 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionExecutors.java @@ -16,6 +16,8 @@ package com.android.server.appfunctions; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -35,6 +37,11 @@ public final class AppFunctionExecutors { /* workQueue= */ new LinkedBlockingQueue<>(), new NamedThreadFactory("AppFunctionExecutors")); + /** Executor for stats logging. */ + public static final ExecutorService LOGGING_THREAD_EXECUTOR = + Executors.newSingleThreadExecutor( + new NamedThreadFactory("AppFunctionsLoggingExecutors")); + static { THREAD_POOL_EXECUTOR.allowCoreThreadTimeOut(true); } diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java index c17c34061d1b..9cc5a8c97258 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java @@ -30,6 +30,7 @@ import android.app.appfunctions.AppFunctionManagerHelper; import android.app.appfunctions.AppFunctionRuntimeMetadata; import android.app.appfunctions.AppFunctionStaticMetadataHelper; import android.app.appfunctions.ExecuteAppFunctionAidlRequest; +import android.app.appfunctions.ExecuteAppFunctionResponse; import android.app.appfunctions.IAppFunctionEnabledCallback; import android.app.appfunctions.IAppFunctionManager; import android.app.appfunctions.IAppFunctionService; @@ -85,6 +86,7 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { private final ServiceConfig mServiceConfig; private final Context mContext; private final Map<String, Object> mLocks = new WeakHashMap<>(); + private final AppFunctionsLoggerWrapper mLoggerWrapper; public AppFunctionManagerServiceImpl(@NonNull Context context) { this( @@ -93,7 +95,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { context, IAppFunctionService.Stub::asInterface, THREAD_POOL_EXECUTOR), new CallerValidatorImpl(context), new ServiceHelperImpl(context), - new ServiceConfigImpl()); + new ServiceConfigImpl(), + new AppFunctionsLoggerWrapper(context)); } @VisibleForTesting @@ -102,12 +105,14 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { RemoteServiceCaller<IAppFunctionService> remoteServiceCaller, CallerValidator callerValidator, ServiceHelper appFunctionInternalServiceHelper, - ServiceConfig serviceConfig) { + ServiceConfig serviceConfig, + AppFunctionsLoggerWrapper loggerWrapper) { mContext = Objects.requireNonNull(context); mRemoteServiceCaller = Objects.requireNonNull(remoteServiceCaller); mCallerValidator = Objects.requireNonNull(callerValidator); mInternalServiceHelper = Objects.requireNonNull(appFunctionInternalServiceHelper); mServiceConfig = serviceConfig; + mLoggerWrapper = loggerWrapper; } /** Called when the user is unlocked. */ @@ -146,8 +151,25 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { Objects.requireNonNull(requestInternal); Objects.requireNonNull(executeAppFunctionCallback); + int callingUid = Binder.getCallingUid(); + int callingPid = Binder.getCallingPid(); + final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback = - new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback); + new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback, + new SafeOneTimeExecuteAppFunctionCallback.CompletionCallback() { + @Override + public void finalizeOnSuccess( + @NonNull ExecuteAppFunctionResponse result) { + mLoggerWrapper.logAppFunctionSuccess(requestInternal, result, + callingUid); + } + + @Override + public void finalizeOnError(@NonNull AppFunctionException error) { + mLoggerWrapper.logAppFunctionError(requestInternal, + error.getErrorCode(), callingUid); + } + }); String validatedCallingPackage; try { @@ -162,9 +184,6 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub { return null; } - int callingUid = Binder.getCallingUid(); - int callingPid = Binder.getCallingPid(); - ICancellationSignal localCancelTransport = CancellationSignal.createTransport(); THREAD_POOL_EXECUTOR.execute( diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java new file mode 100644 index 000000000000..b59915aa6343 --- /dev/null +++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 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.appfunctions; + +import static com.android.server.appfunctions.AppFunctionExecutors.LOGGING_THREAD_EXECUTOR; + +import android.annotation.NonNull; +import android.app.appfunctions.ExecuteAppFunctionAidlRequest; +import android.app.appfunctions.ExecuteAppFunctionResponse; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.SystemClock; +import android.util.Slog; + +import java.util.Objects; + +/** Wraps AppFunctionsStatsLog. */ +public class AppFunctionsLoggerWrapper { + private static final String TAG = AppFunctionsLoggerWrapper.class.getSimpleName(); + + private static final int SUCCESS_RESPONSE_CODE = -1; + + private final Context mContext; + + public AppFunctionsLoggerWrapper(@NonNull Context context) { + mContext = Objects.requireNonNull(context); + } + + void logAppFunctionSuccess(ExecuteAppFunctionAidlRequest request, + ExecuteAppFunctionResponse response, int callingUid) { + logAppFunctionsRequestReported(request, SUCCESS_RESPONSE_CODE, + response.getResponseDataSize(), callingUid); + } + + void logAppFunctionError(ExecuteAppFunctionAidlRequest request, int errorCode, int callingUid) { + logAppFunctionsRequestReported(request, errorCode, /* responseSizeBytes = */ 0, callingUid); + } + + private void logAppFunctionsRequestReported(ExecuteAppFunctionAidlRequest request, + int errorCode, int responseSizeBytes, int callingUid) { + final long latency = SystemClock.elapsedRealtime() - request.getRequestTime(); + LOGGING_THREAD_EXECUTOR.execute(() -> AppFunctionsStatsLog.write( + AppFunctionsStatsLog.APP_FUNCTIONS_REQUEST_REPORTED, + callingUid, + getPackageUid(request.getClientRequest().getTargetPackageName()), + errorCode, + request.getClientRequest().getRequestDataSize(), responseSizeBytes, + latency) + ); + } + + private int getPackageUid(String packageName) { + try { + return mContext.getPackageManager().getPackageUid(packageName, 0); + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "Package uid not found for " + packageName); + } + return 0; + } +} diff --git a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java index c689bb92f8f7..896c0fc51683 100644 --- a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java +++ b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java @@ -16,8 +16,8 @@ package com.android.server.appfunctions; import android.annotation.NonNull; -import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.app.appfunctions.AppFunctionException; +import android.app.appfunctions.ExecuteAppFunctionAidlRequest; import android.app.appfunctions.ExecuteAppFunctionResponse; import android.app.appfunctions.IAppFunctionService; import android.app.appfunctions.ICancellationCallback; |