From 4b7d9b148be5ffdef55b8053214defbe21bf1c61 Mon Sep 17 00:00:00 2001 From: Lalit Maganti Date: Fri, 10 Dec 2021 21:19:56 +0000 Subject: [PATCH] base: add support for routing traces to reporters Change-Id: I4ff55e9c211bfedada85234ee86f7484acf633ee --- core/api/system-current.txt | 17 ++ core/java/Android.bp | 5 + .../service/tracing/TraceReportService.java | 165 ++++++++++++++++++ .../android/tracing/ITracingServiceProxy.aidl | 12 +- .../android/tracing/TraceReportParams.aidl | 59 +++++++ core/res/AndroidManifest.xml | 7 + libs/tracingproxy/Android.bp | 1 + .../server/tracing/TracingServiceProxy.java | 162 ++++++++++++++++- 8 files changed, 417 insertions(+), 11 deletions(-) create mode 100644 core/java/android/service/tracing/TraceReportService.java create mode 100644 core/java/android/tracing/TraceReportParams.aidl diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 61b4ada0c5dd..59511510e467 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -63,6 +63,7 @@ package android { field public static final String BIND_TELEPHONY_NETWORK_SERVICE = "android.permission.BIND_TELEPHONY_NETWORK_SERVICE"; field public static final String BIND_TEXTCLASSIFIER_SERVICE = "android.permission.BIND_TEXTCLASSIFIER_SERVICE"; field public static final String BIND_TIME_ZONE_PROVIDER_SERVICE = "android.permission.BIND_TIME_ZONE_PROVIDER_SERVICE"; + field public static final String BIND_TRACE_REPORT_SERVICE = "android.permission.BIND_TRACE_REPORT_SERVICE"; field public static final String BIND_TRANSLATION_SERVICE = "android.permission.BIND_TRANSLATION_SERVICE"; field public static final String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT"; field public static final String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE"; @@ -10120,6 +10121,22 @@ package android.service.timezone { } +package android.service.tracing { + + public class TraceReportService extends android.app.Service { + ctor public TraceReportService(); + method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); + method public boolean onMessage(@NonNull android.os.Message); + method public void onReportTrace(@NonNull android.service.tracing.TraceReportService.TraceParams); + } + + public static final class TraceReportService.TraceParams { + method @NonNull public android.os.ParcelFileDescriptor getFd(); + method @NonNull public java.util.UUID getUuid(); + } + +} + package android.service.translation { public abstract class TranslationService extends android.app.Service { diff --git a/core/java/Android.bp b/core/java/Android.bp index 343830a468dc..72a432eedaaa 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -33,6 +33,11 @@ filegroup { srcs: ["android/tracing/ITracingServiceProxy.aidl"], } +filegroup { + name: "TraceReportParams.aidl", + srcs: ["android/tracing/TraceReportParams.aidl"], +} + // These are subset of framework-core-sources that are needed by the // android.test.mock library. The implementation of android.test.mock references // private members of various components to allow mocking of classes that cannot diff --git a/core/java/android/service/tracing/TraceReportService.java b/core/java/android/service/tracing/TraceReportService.java new file mode 100644 index 000000000000..3d16a3d41ea3 --- /dev/null +++ b/core/java/android/service/tracing/TraceReportService.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2021 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 android.service.tracing; + +import static android.annotation.SystemApi.Client.PRIVILEGED_APPS; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.ParcelFileDescriptor; +import android.os.Process; +import android.tracing.TraceReportParams; +import android.util.Log; + +import java.io.IOException; +import java.util.UUID; + +/** + * Service to be sub-classed and exposed by (privileged) apps which want to report + * system traces. + *

+ * Subclasses should implement the onReportTrace method to handle traces reported + * to them. + *

+ *
+ *    public class SampleReportService extends TraceReportService {
+ *        public void onReportTrace(TraceParams args) {
+ *            // --- Implementation goes here ---
+ *        }
+ *    }
+ * 
+ *

+ * The service declaration in the application manifest must specify + * BIND_TRACE_REPORT_SERVICE in the permission attribute. + *

+ *
+ *   <application>
+ *        <service android:name=".SampleReportService"
+ *               android:permission="android.permission.BIND_TRACE_REPORT_SERVICE">
+ *       </service>
+ *   </application>
+ * 
+ * + * Moreover, the package containing this service must hold the DUMP and PACKAGE_USAGE_STATS + * permissions. + * + * @hide + */ +@SystemApi(client = PRIVILEGED_APPS) +public class TraceReportService extends Service { + private static final String TAG = "TraceReportService"; + private Messenger mMessenger = null; + + /** + * Public to allow this to be used by TracingServiceProxy in system_server. + * + * @hide + */ + public static final int MSG_REPORT_TRACE = 1; + + /** + * Contains information about the trace which is being reported. + * + * @hide + */ + @SystemApi(client = PRIVILEGED_APPS) + public static final class TraceParams { + private final ParcelFileDescriptor mFd; + private final UUID mUuid; + + private TraceParams(TraceReportParams params) { + mFd = params.fd; + mUuid = new UUID(params.uuidMsb, params.uuidLsb); + } + + /** + * Returns the ParcelFileDescriptor for the collected trace. + */ + @NonNull + public ParcelFileDescriptor getFd() { + return mFd; + } + + /** + * Returns the UUID of the trace; this is exactly the UUID created by the tracing system + * (i.e. Perfetto) and is also present inside the trace file. + */ + @NonNull + public UUID getUuid() { + return mUuid; + } + } + + // Methods to override. + /** + * Called when a trace is reported and sent to this class. + * + * Note: the trace file descriptor should not be persisted beyond the lifetime of this + * function as it is owned by the framework and will be closed immediately after this function + * returns: if future use of the fd is needed, it should be duped. + */ + public void onReportTrace(@NonNull TraceParams args) { + } + + // Optional methods to override. + // Realistically, these methods are internal implementation details but since this class is + // a SystemApi, it's better to err on the side of flexibility just in-case we need to override + // these methods down the line. + + /** + * Handles binder calls from system_server. + */ + public boolean onMessage(@NonNull Message msg) { + if (msg.what == MSG_REPORT_TRACE) { + if (!(msg.obj instanceof TraceReportParams)) { + Log.e(TAG, "Received invalid type for report trace message."); + return false; + } + TraceParams params = new TraceParams((TraceReportParams) msg.obj); + try { + onReportTrace(params); + } finally { + try { + params.getFd().close(); + } catch (IOException ignored) { + } + } + return true; + } + return false; + } + + /** + * Returns an IBinder for handling binder calls from system_server. + */ + @Nullable + @Override + public IBinder onBind(@NonNull Intent intent) { + if (mMessenger == null) { + mMessenger = new Messenger(new Handler(Looper.getMainLooper(), this::onMessage)); + } + return mMessenger.getBinder(); + } +} \ No newline at end of file diff --git a/core/java/android/tracing/ITracingServiceProxy.aidl b/core/java/android/tracing/ITracingServiceProxy.aidl index 4520db3915a2..8029b88226b0 100644 --- a/core/java/android/tracing/ITracingServiceProxy.aidl +++ b/core/java/android/tracing/ITracingServiceProxy.aidl @@ -16,17 +16,25 @@ package android.tracing; +import android.tracing.TraceReportParams; + /** * Binder interface for the TracingServiceProxy running in system_server. * * {@hide} */ -interface ITracingServiceProxy -{ +interface ITracingServiceProxy { /** * Notifies system tracing app that a tracing session has ended. If a session is repurposed * for use in a bugreport, sessionStolen can be set to indicate that tracing has ended but * there is no buffer available to dump. */ oneway void notifyTraceSessionEnded(boolean sessionStolen); + + /** + * Notifies the specified service that a trace has been captured. The contents of |params| + * contains the intended recipient (package and class) of this trace as well as a file + * descriptor to an unlinked trace |fd| (i.e. an fd opened using O_TMPFILE). + */ + oneway void reportTrace(in TraceReportParams params); } diff --git a/core/java/android/tracing/TraceReportParams.aidl b/core/java/android/tracing/TraceReportParams.aidl new file mode 100644 index 000000000000..f57386c087ea --- /dev/null +++ b/core/java/android/tracing/TraceReportParams.aidl @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2021, 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 android.tracing; + +import android.os.ParcelFileDescriptor; + +/* + * Parameters for a trace report. + * + * See ITracingServiceProxy::reportTrace for more details. + * + * @hide + */ +parcelable TraceReportParams { + // The package name containing the reporter service (see |reporterClassName|). + String reporterPackageName; + + // The class name of the reporter service. The framework will bind to this service and pass the + // trace fd and metadata to this class. + // This class should be "trusted" (in practice this means being a priv_app + having DUMP and + // USAGE_STATS permissions). + String reporterClassName; + + // The file descriptor for the trace file. This will be an unlinked file fd (i.e. created + // with O_TMPFILE); the intention is that reporter classes link this fd into a app-private + // folder for reporting when conditions are right (e.g. charging, on unmetered networks etc). + ParcelFileDescriptor fd; + + // The least-significant-bytes of the UUID of this trace. + long uuidLsb; + + // The most-significant-bytes of the UUID of this trace. + long uuidMsb; + + // Flag indicating whether, instead of passing the fd from the trace collector, to pass a + // pipe fd from system_server and send the file over it. + // + // This flag is necessary because there is no good way to write a CTS test where a helper + // priv_app (in terms of SELinux) is needed (this is because priv_apps are supposed to be + // preinstalled on the system partition). By creating a pipe in system_server we work around + // this restriction. Note that there is a maximum allowed file size if this flag is set + // (see TracingServiceProxy). Further note that, even though SELinux may be worked around, + // manifest (i.e. framework) permissions are still checked even if this flag is set. + boolean usePipeForTesting; +} \ No newline at end of file diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 6bcaace96cbe..7f95ca912366 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3453,6 +3453,13 @@ + + +