Developer Profiling APIs

Add APIs only as no-op

Test: m, presubmit
API-Coverage-Bug: 293957254
Bug: 293957254
Change-Id: Ie627e672f46fbae89997f90c1ad9fc3de04f8d5f
diff --git a/framework/api/current.txt b/framework/api/current.txt
index d802177..97afd77 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -1 +1,30 @@
 // Signature format: 2.0
+package android.os {
+
+  @FlaggedApi("android.os.profiling.telemetry_apis") public class ProfilingManager {
+    method public void registerForProfilingResults(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.os.ProfilingResult>);
+    method public void requestProfiling(@NonNull byte[], @Nullable String, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<android.os.ProfilingResult>);
+    method public void unregisterForProfilingResults(@Nullable java.util.function.Consumer<android.os.ProfilingResult>);
+  }
+
+  @FlaggedApi("android.os.profiling.telemetry_apis") public final class ProfilingResult implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getErrorCode();
+    method @Nullable public String getErrorMessage();
+    method @Nullable public String getResultFilePath();
+    method @Nullable public String getTag();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.os.ProfilingResult> CREATOR;
+    field public static final int ERROR_FAILED_EXECUTING = 4; // 0x4
+    field public static final int ERROR_FAILED_INVALID_REQUEST = 7; // 0x7
+    field public static final int ERROR_FAILED_NO_DISK_SPACE = 6; // 0x6
+    field public static final int ERROR_FAILED_POST_PROCESSING = 5; // 0x5
+    field public static final int ERROR_FAILED_PROFILING_IN_PROGRESS = 3; // 0x3
+    field public static final int ERROR_FAILED_RATE_LIMIT_PROCESS = 2; // 0x2
+    field public static final int ERROR_FAILED_RATE_LIMIT_SYSTEM = 1; // 0x1
+    field public static final int ERROR_NONE = 0; // 0x0
+    field public static final int ERROR_UNKNOWN = 8; // 0x8
+  }
+
+}
+
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index d802177..2f6a35a 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -1 +1,10 @@
 // Signature format: 2.0
+package android.os {
+
+  @FlaggedApi("android.os.profiling.telemetry_apis") public class ProfilingFrameworkInitializer {
+    method public static void registerServiceWrappers();
+    method public static void setProfilingServiceManager(@NonNull android.os.ProfilingServiceManager);
+  }
+
+}
+
diff --git a/framework/java/android/os/ProfilingFrameworkInitializer.java b/framework/java/android/os/ProfilingFrameworkInitializer.java
new file mode 100644
index 0000000..fd50f81
--- /dev/null
+++ b/framework/java/android/os/ProfilingFrameworkInitializer.java
@@ -0,0 +1,80 @@
+/*
+ * 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 android.os;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
+import android.app.SystemServiceRegistry;
+import android.content.Context;
+import android.os.ProfilingManager;
+import android.os.profiling.Flags;
+
+/**
+ * Class for performing registration for profiling service.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_TELEMETRY_APIS)
+@SystemApi(client = Client.MODULE_LIBRARIES)
+public class ProfilingFrameworkInitializer {
+
+    private ProfilingFrameworkInitializer() {}
+
+    private static volatile ProfilingServiceManager sProfilingServiceManager;
+
+    /**
+     * Sets an instance of {@link ProfilingServiceManager} that allows the profiling module to
+     * register/obtain profiling binder services. This is called by the platform during the system
+     * initialization.
+     *
+     * @param profilingServiceManager instance of {@link ProfilingServiceManager} that allows the
+     * profiling module to register/obtain profiling binder services.
+     */
+    public static void setProfilingServiceManager(
+            @NonNull ProfilingServiceManager profilingServiceManager) {
+        if (sProfilingServiceManager != null) {
+            throw new IllegalStateException("setProfilingServiceManager called twice!");
+        }
+
+        if (profilingServiceManager == null) {
+            throw new NullPointerException("profilingServiceManager is null");
+        }
+
+        sProfilingServiceManager = profilingServiceManager;
+    }
+
+    /** @hide */
+    public static ProfilingServiceManager getProfilingServiceManager() {
+        return sProfilingServiceManager;
+    }
+
+    /**
+     * Called by {@link SystemServiceRegistry}'s static initializer and registers profiling
+     * services to {@link Context}, so that {@link Context#getSystemService} can return them.
+     *
+     * @throws IllegalStateException if this is called from anywhere besides
+     * {@link SystemServiceRegistry}
+     */
+    public static void registerServiceWrappers() {
+        SystemServiceRegistry.registerContextAwareService(
+                Context.PROFILING_SERVICE,
+                ProfilingManager.class,
+                context -> new ProfilingManager(context)
+        );
+    }
+}
diff --git a/framework/java/android/os/ProfilingManager.java b/framework/java/android/os/ProfilingManager.java
index 51dab7a..9052567 100644
--- a/framework/java/android/os/ProfilingManager.java
+++ b/framework/java/android/os/ProfilingManager.java
@@ -15,8 +15,76 @@
  */
 package android.os;
 
-/** @hide */
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.OutcomeReceiver;
+import android.os.profiling.Flags;
+
+import java.lang.Exception;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * API for apps to request and listen for app specific profiling.
+ */
+@FlaggedApi(Flags.FLAG_TELEMETRY_APIS)
 public class ProfilingManager {
-    /** @hide **/
-    public void placeholder() {}
+
+    /** @hide */
+    public ProfilingManager(Context context) {}
+
+    /**
+     * Request profiling via perfetto.
+     *
+     * <p class="note"> Note: use of this API directly is not recommended for most use cases.
+     * Please use the higher level wrappers provided by androidx that will construct the request
+     * correctly based on available options and simplified user provided request parameters.</p>
+     *
+     * <p class="note"> Note: requests are not guaranteed to be filled.</p>
+     *
+     * <p class="note"> Note: a listener must be set for the request to be considered for
+     * fulfillment. Listeners can be set in this method, with {@see #registerForProfilingResult},
+     * or both. If no listener is set the request will be discarded.</p>
+     *
+     * @param profilingRequest byte array representation of ProfilingRequest proto containing all
+     *                         necessary information about the collection being requested.
+     * @param tag Caller defined data to help identify the output.
+     * @param cancellationSignal for caller requested cancellation.
+     * @param executor The executor to call back with.
+     * @param listener Listener to be triggered with result.
+     */
+    public void requestProfiling(
+            @NonNull byte[] profilingRequest,
+            @Nullable String tag,
+            @Nullable CancellationSignal cancellationSignal,
+            @Nullable Executor executor,
+            @Nullable Consumer<ProfilingResult> listener) {
+        // TODO b/293957254
+    }
+
+    /**
+     * Register a listener to be called for all profiling results.
+     *
+     * @param executor The executor to call back with.
+     * @param listener Listener to be triggered with result.
+     */
+    public void registerForProfilingResults(
+            @NonNull Executor executor,
+            @NonNull Consumer<ProfilingResult> listener) {
+        // TODO b/293957254
+    }
+
+    /**
+     * Unregister a listener to be called for all profiling results. If no listener is provided,
+     * all listeners for this process that were not submitted with a currently running trace will
+     * be removed.
+     *
+     * @param listener Listener to unregister and no longer be triggered with the result.
+     */
+    public void unregisterForProfilingResults(
+            @Nullable Consumer<ProfilingResult> listener) {
+        // TODO b/293957254
+    }
 }
diff --git a/framework/java/android/os/ProfilingResult.java b/framework/java/android/os/ProfilingResult.java
new file mode 100644
index 0000000..1e633df
--- /dev/null
+++ b/framework/java/android/os/ProfilingResult.java
@@ -0,0 +1,159 @@
+/*
+ * 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 android.os;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.profiling.Flags;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Encapsulates results of a single profiling request operation.
+ */
+@FlaggedApi(Flags.FLAG_TELEMETRY_APIS)
+public final class ProfilingResult implements Parcelable {
+
+    /** @see #getErrorCode */
+    final @ErrorCode int mErrorCode;
+
+    /** @see #getResultFilePath */
+    @Nullable final String mResultFilePath;
+
+    /** @see #getTag */
+    @Nullable final String mTag;
+
+    /** @see #getErrorMessage */
+    @Nullable final String mErrorMessage;
+
+    /** The request was executed and succeeded. */
+    public final static int ERROR_NONE = 0;
+
+    /** The request was denied due to system level rate limiting. */
+    public final static int ERROR_FAILED_RATE_LIMIT_SYSTEM = 1;
+
+    /** The request was denied due to process level rate limiting. */
+    public final static int ERROR_FAILED_RATE_LIMIT_PROCESS = 2;
+
+    /** The request was denied due to profiling already in progress. */
+    public final static int ERROR_FAILED_PROFILING_IN_PROGRESS = 3;
+
+    /** The request was executed and failed for a reason not specified below. */
+    public final static int ERROR_FAILED_EXECUTING = 4;
+
+    /** The request was executed but post processing failed and the result was discarded. */
+    public final static int ERROR_FAILED_POST_PROCESSING = 5;
+
+    /** The request was executed and failed due to a lack of disk space. */
+    public final static int ERROR_FAILED_NO_DISK_SPACE = 6;
+
+    /** The request failed due to invalid ProfilingRequest. */
+    public final static int ERROR_FAILED_INVALID_REQUEST = 7;
+
+    /** The request was denied or failed for an unspecified reason. */
+    public final static int ERROR_UNKNOWN = 8;
+
+    /** @hide */
+    @IntDef(value={
+            ERROR_NONE,
+            ERROR_FAILED_RATE_LIMIT_SYSTEM,
+            ERROR_FAILED_RATE_LIMIT_PROCESS,
+            ERROR_FAILED_PROFILING_IN_PROGRESS,
+            ERROR_FAILED_EXECUTING,
+            ERROR_FAILED_POST_PROCESSING,
+            ERROR_FAILED_NO_DISK_SPACE,
+            ERROR_UNKNOWN,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ErrorCode {}
+
+    ProfilingResult(@ErrorCode int errorCode, String resultFilePath, String tag,
+            String errorMessage) {
+        mErrorCode = errorCode;
+        mResultFilePath = resultFilePath;
+        mTag = tag;
+        mErrorMessage = errorMessage;
+    }
+
+    private ProfilingResult(@NonNull Parcel in) {
+        mErrorCode = in.readInt();
+        mResultFilePath = in.readString();
+        mTag = in.readString();
+        mErrorMessage = in.readString();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mErrorCode);
+        dest.writeString(mResultFilePath);
+        dest.writeString(mTag);
+        dest.writeString(mErrorMessage);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public @NonNull static final Creator<ProfilingResult> CREATOR =
+            new Creator<ProfilingResult>() {
+                @Override
+                public ProfilingResult createFromParcel(Parcel in) {
+                    return new ProfilingResult(in);
+                }
+
+                @Override
+                public ProfilingResult[] newArray(int size) {
+                    return new ProfilingResult[size];
+                }
+            };
+
+    /**
+     * The result ErrorCode for the profiling request indicating the failure reason if applicable.
+     */
+    public @ErrorCode int getErrorCode() {
+        return mErrorCode;
+    }
+
+    /**
+     * The file path of the profiling result data.
+     *
+     * Will be null if {@see #getErrorCode} returns code other than {@see #ERROR_NONE}.
+     */
+    public @Nullable String getResultFilePath() {
+        return mResultFilePath;
+    }
+
+    /**
+     * The tag defined by the caller at request time.
+     */
+    public @Nullable String getTag() {
+        return mTag;
+    }
+
+  /**
+   * Additional details about failures that occurred, if applicable.
+   */
+  public @Nullable String getErrorMessage() {
+      return mErrorMessage;
+  }
+}