Add Service tests for Profiling

- Add tests for ProfilingService covering up to but not including starting the trace (starting trace cannot be done from this context and will be covered in subsequent ProifilingManager tsts)
- Rework rate limiter to not be static for better testability (this will also help with a cleaner persisting impl)

Test: run new tests, presubmit, manual test
Bug: 293957254
Change-Id: If735259c3c1cc85752917e0e8606e94c63447286
diff --git a/service/java/com/android/os/profiling/ProfilingService.java b/service/java/com/android/os/profiling/ProfilingService.java
index ef6c51b..9864376 100644
--- a/service/java/com/android/os/profiling/ProfilingService.java
+++ b/service/java/com/android/os/profiling/ProfilingService.java
@@ -71,21 +71,25 @@
     private final int PERFETTO_DESTROY_TIMEOUT_MS;
 
     private final Context mContext;
+    @VisibleForTesting public RateLimiter mRateLimiter;
 
     private final HandlerThread mHandlerThread = new HandlerThread("ProfilingService");
     private Handler mHandler;
 
+
     // uid indexed collecion of JNI callbacks for results.
-    private @Nullable SparseArray<IProfilingResultCallback> mResultCallbacks = new SparseArray<>();
+    @VisibleForTesting
+    public SparseArray<IProfilingResultCallback> mResultCallbacks = new SparseArray<>();
 
     // Request UUID key indexed storage of active tracing sessions. Currently only 1 active session
     // is supported at a time, but this will be used in future to support multiple.
-    private ArrayMap<String, TracingSession> mTracingSessions = new ArrayMap<>();
+    @VisibleForTesting
+    public ArrayMap<String, TracingSession> mTracingSessions = new ArrayMap<>();
 
     @VisibleForTesting
     public ProfilingService(Context context) {
         mContext = context;
-        RateLimiter.loadFromDisk();
+        mRateLimiter = new RateLimiter(context);
         PERFETTO_DESTROY_TIMEOUT_MS = PERFETTO_DESTROY_DEFAULT_TIMEOUT_MS;
         mHandlerThread.start();
     }
@@ -134,7 +138,8 @@
         }
 
         // Check with rate limiter if this request is allowed.
-        final int status = RateLimiter.isProfilingRequestAllowed(Binder.getCallingUid(), request);
+        final int status = mRateLimiter.isProfilingRequestAllowed(Binder.getCallingUid(), request);
+        if (DEBUG) Log.d(TAG, "Rate limiter status: " + status);
         if (status == RateLimiter.RATE_LIMIT_RESULT_ALLOWED) {
             // Rate limiter approved, try to start the request.
             try {
@@ -248,7 +253,7 @@
         getHandler().postDelayed(session.getProcessResultRunnable(), postProcessingDelayMs);
     }
 
-    public void stopProfiling(String key) throws RuntimeException {
+    private void stopProfiling(String key) throws RuntimeException {
         TracingSession session = mTracingSessions.get(key);
         if (session == null || session.getActiveTrace() == null) {
             if (DEBUG) Log.d(TAG, "No active trace, nothing to stop.");
diff --git a/service/java/com/android/os/profiling/RateLimiter.java b/service/java/com/android/os/profiling/RateLimiter.java
index 2fdcf42..350575d 100644
--- a/service/java/com/android/os/profiling/RateLimiter.java
+++ b/service/java/com/android/os/profiling/RateLimiter.java
@@ -26,12 +26,12 @@
 import java.util.ArrayDeque;
 import java.util.Queue;
 
-public final class RateLimiter {
+import android.content.Context;
+
+public class RateLimiter {
 
     private static final String DEVICE_CONFIG_NAMESPACE = "profiling";
 
-    private static final long PERSIST_TO_DISK_FREQUENCY_MS;
-
     private static final long TIME_1_HOUR_MS = 60 * 60 * 1000;
     private static final long TIME_24_HOUR_MS = 24 * 60 * 60 * 1000;
     private static final long TIME_7_DAY_MS = 7 * 24 * 60 * 60 * 1000;
@@ -40,17 +40,19 @@
     public static final int RATE_LIMIT_RESULT_BLOCKED_PROCESS = 1;
     public static final int RATE_LIMIT_RESULT_BLOCKED_SYSTEM = 2;
 
+    private final long mPersistToDiskFrequency;
+
     /** To be disabled for testing only. */
-    private static boolean sRateLimiterEnabled = true;
+    private boolean mRateLimiterEnabled = true;
 
     /** Collection of run costs and entries from the last hour. */
-    private static final EntryGroupWrapper sPastRuns1Hour;
+    private final EntryGroupWrapper mPastRuns1Hour;
     /** Collection of run costs and entries from the 24 hours. */
-    private static final EntryGroupWrapper sPastRuns24Hour;
+    private final EntryGroupWrapper mPastRuns24Hour;
     /** Collection of run costs and entries from the 7 days. */
-    private static final EntryGroupWrapper sPastRuns7Day;
+    private final EntryGroupWrapper mPastRuns7Day;
 
-    private static long sLastPersistedTimestampMs;
+    private long mLastPersistedTimestampMs;
 
     @IntDef(value={
         RATE_LIMIT_RESULT_ALLOWED,
@@ -60,55 +62,57 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface RateLimitResult {}
 
-    static {
+
+    public RateLimiter(Context context) {
         // TODO: b/324885858 use DeviceConfig for adjustable values.
-        sPastRuns1Hour = new EntryGroupWrapper(10, 10, TIME_1_HOUR_MS);
-        sPastRuns24Hour = new EntryGroupWrapper(100, 100, TIME_24_HOUR_MS);
-        sPastRuns7Day = new EntryGroupWrapper(1000, 1000, TIME_7_DAY_MS);
-        PERSIST_TO_DISK_FREQUENCY_MS = 0;
-        sLastPersistedTimestampMs = System.currentTimeMillis();
+        mPastRuns1Hour = new EntryGroupWrapper(10, 10, TIME_1_HOUR_MS);
+        mPastRuns24Hour = new EntryGroupWrapper(100, 100, TIME_24_HOUR_MS);
+        mPastRuns7Day = new EntryGroupWrapper(1000, 1000, TIME_7_DAY_MS);
+        mPersistToDiskFrequency = 0;
+        mLastPersistedTimestampMs = System.currentTimeMillis();
+        loadFromDisk();
     }
 
-    public static @RateLimitResult int isProfilingRequestAllowed(int uid,
+    public @RateLimitResult int isProfilingRequestAllowed(int uid,
             ProfilingRequest request) {
-        if (!sRateLimiterEnabled) {
+        if (!mRateLimiterEnabled) {
             // Rate limiter is disabled for testing, approve request and don't store cost.
             return RATE_LIMIT_RESULT_ALLOWED;
         }
         final int cost = 1; // TODO: compute cost b/293957254
         final long currentTimeMillis = System.currentTimeMillis();
-        int status = sPastRuns1Hour.isProfilingAllowed(uid, cost, currentTimeMillis);
+        int status = mPastRuns1Hour.isProfilingAllowed(uid, cost, currentTimeMillis);
         if (status == RATE_LIMIT_RESULT_ALLOWED) {
-            status = sPastRuns24Hour.isProfilingAllowed(uid, cost, currentTimeMillis);
+            status = mPastRuns24Hour.isProfilingAllowed(uid, cost, currentTimeMillis);
         }
         if (status == RATE_LIMIT_RESULT_ALLOWED) {
-            status = sPastRuns7Day.isProfilingAllowed(uid, cost, currentTimeMillis);
+            status = mPastRuns7Day.isProfilingAllowed(uid, cost, currentTimeMillis);
         }
         if (status == RATE_LIMIT_RESULT_ALLOWED) {
-            sPastRuns1Hour.add(uid, cost, currentTimeMillis);
-            sPastRuns24Hour.add(uid, cost, currentTimeMillis);
-            sPastRuns7Day.add(uid, cost, currentTimeMillis);
+            mPastRuns1Hour.add(uid, cost, currentTimeMillis);
+            mPastRuns24Hour.add(uid, cost, currentTimeMillis);
+            mPastRuns7Day.add(uid, cost, currentTimeMillis);
             maybePersistToDisk();
             return RATE_LIMIT_RESULT_ALLOWED;
         }
         return status;
     }
 
-    static void maybePersistToDisk() {
-        if (PERSIST_TO_DISK_FREQUENCY_MS == 0
-                || System.currentTimeMillis() - sLastPersistedTimestampMs
-                >= PERSIST_TO_DISK_FREQUENCY_MS) {
+    void maybePersistToDisk() {
+        if (mPersistToDiskFrequency == 0
+                || System.currentTimeMillis() - mLastPersistedTimestampMs
+                >= mPersistToDiskFrequency) {
             persistToDisk();
         } else {
             // TODO: queue persist job b/293957254
         }
     }
 
-    static void persistToDisk() {
+    void persistToDisk() {
         // TODO: b/293957254
     }
 
-    static void loadFromDisk() {
+    void loadFromDisk() {
         // TODO: b/293957254
     }
 
diff --git a/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java b/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java
index 75aa014..b19233d 100644
--- a/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java
+++ b/tests/cts/src/android/profiling/cts/ProfilingServiceTests.java
@@ -18,17 +18,48 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
+import static org.mockito.Mockito.reset;
 
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyObject;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.os.IProfilingResultCallback;
+import android.os.ParcelFileDescriptor;
+import android.os.Binder;
+import android.content.pm.PackageManager;
+import android.app.UiAutomation;
+import android.os.profiling.RateLimiter;
+import android.os.profiling.TracingSession;
+import android.os.ProfilingRequest;
+import android.os.ProfilingResult;
 import android.os.profiling.ProfilingService;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
 
+import java.lang.Process;
+import java.util.UUID;
+
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
 import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 /**
  * Tests in this class are for testing the ProfilingService directly without the need to get a
@@ -37,24 +68,253 @@
 
 @RunWith(AndroidJUnit4.class)
 public final class ProfilingServiceTests {
+
+    private static final String APP_FILE_PATH = "/data/user/0/com.profiling.test/files";
+    private static final String APP_PACKAGE_NAME = "com.profiling.test";
+    private static final String REQUEST_TAG = "some unique string";
+
+    // Key most and least significant bits are used to generate a unique key specific to each
+    // request. Key is used to pair request back to caller and callbacks so test to keep consistent.
+    private static final long KEY_MOST_SIG_BITS = 456l;
+    private static final long KEY_LEAST_SIG_BITS = 123l;
+
     @Rule
     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-    private ProfilingService mProfilingService =
-            new ProfilingService(ApplicationProvider.getApplicationContext());
 
-    @Test
-    public void createProfilingServiceTest() {
-    assertThat(mProfilingService).isNotNull();
-  }
+    @Mock private PackageManager mPackageManager;
+    @Mock private Process mActiveTrace;
 
+    private Context mContext = ApplicationProvider.getApplicationContext();
+    private ProfilingService mProfilingService;
+    private RateLimiter mRateLimiter;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        mProfilingService = spy(new ProfilingService(mContext));
+        mRateLimiter = spy(new RateLimiter(mContext));
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        mProfilingService.mRateLimiter = mRateLimiter;
+        doReturn(APP_PACKAGE_NAME).when(mPackageManager).getNameForUid(anyInt());
+    }
+
+    /** Test that registering binder callbacks works as expected. */
     @Test
-    public void profilingNotRunningTests() {
-      try {
-        boolean isRunning = mProfilingService.areAnyTracesRunning();
-        assertThat(isRunning).isFalse();
-      } catch (Exception exception) {
-        assertThat(exception).isInstanceOf(RuntimeException.class);
-      }
+    public void testRegisterResultCallback() {
+        ProfilingResultCallback callback = new ProfilingResultCallback();
+
+        // Register callback.
+        mProfilingService.registerResultsCallback(callback);
+
+        // Confirm callback is registered.
+        assertEquals(callback, mProfilingService.mResultCallbacks.get(Binder.getCallingUid()));
+    }
+
+    /**
+     * Test that requesting profiling while another profiling is in progress fails with correct
+     * error codes.
+     */
+    @Test
+    public void testRequestProfiling_ProfilingRunning_Fails() {
+        // Mock traces running check to simulate collection running.
+        doReturn(true).when(mProfilingService).areAnyTracesRunning();
+
+        // Register callback.
+        ProfilingResultCallback callback = new ProfilingResultCallback();
+        mProfilingService.registerResultsCallback(callback);
+
+        // Kick off request.
+        mProfilingService.requestProfiling(ProfilingTestUtils.getJavaHeapDumpProfilingRequest(),
+                APP_FILE_PATH, REQUEST_TAG, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+
+        // Confirm result matches failure expectation.
+        confirmResultCallback(callback, null, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS,
+                ProfilingResult.ERROR_FAILED_PROFILING_IN_PROGRESS, REQUEST_TAG, false);
+    }
+
+    /**
+     * Test that requesting profiling with an invalid request byte array fails with correct error
+     * codes.
+     */
+    @Test
+    public void testRequestProfiling_InvalidRequest_Fails() {
+        // Bypass traces running check, we're not testing that here.
+        doReturn(false).when(mProfilingService).areAnyTracesRunning();
+
+        // Register callback.
+        ProfilingResultCallback callback = new ProfilingResultCallback();
+        mProfilingService.registerResultsCallback(callback);
+
+        // Kick off request.
+        mProfilingService.requestProfiling(new byte[4], APP_FILE_PATH, REQUEST_TAG,
+                KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+
+        // Confirm result matches failure expectation.
+        confirmResultCallback(callback, null, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS,
+                ProfilingResult.ERROR_FAILED_INVALID_REQUEST, REQUEST_TAG, true);
+    }
+
+    /** Test that requesting where we cannot access the package name fails. */
+    @Test
+    public void testRequestProfiling_PackageNameNotFound_Fails() {
+        // Mock getNameForUid to simulate failure case.
+        doReturn(null).when(mPackageManager).getNameForUid(anyInt());
+
+        // Register callback.
+        ProfilingResultCallback callback = new ProfilingResultCallback();
+        mProfilingService.registerResultsCallback(callback);
+
+        // Kick off request.
+        mProfilingService.requestProfiling(ProfilingTestUtils.getJavaHeapDumpProfilingRequest(),
+                APP_FILE_PATH, REQUEST_TAG, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+
+        // Confirm result matches failure expectation.
+        confirmResultCallback(callback, null, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS,
+                ProfilingResult.ERROR_UNKNOWN, REQUEST_TAG, true);
+    }
+
+    /** Test that failing rate limiting blocks trace from running. */
+    @Test
+    public void testRequestProfiling_RateLimitBlocked_Fails() {
+        // Bypass traces running check, we're not testing that here.
+        doReturn(false).when(mProfilingService).areAnyTracesRunning();
+
+        // Mock rate limiter result to simulate failure case.
+        doReturn(RateLimiter.RATE_LIMIT_RESULT_BLOCKED_PROCESS).when(mRateLimiter)
+              .isProfilingRequestAllowed(anyInt(), anyObject());
+
+        // Register callback.
+        ProfilingResultCallback callback = new ProfilingResultCallback();
+        mProfilingService.registerResultsCallback(callback);
+
+        // Kick off request.
+        mProfilingService.requestProfiling(ProfilingTestUtils.getJavaHeapDumpProfilingRequest(),
+                APP_FILE_PATH, REQUEST_TAG, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+
+        // Confirm result matches failure expectation.
+        confirmResultCallback(callback, null, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS,
+                ProfilingResult.ERROR_FAILED_RATE_LIMIT_PROCESS, REQUEST_TAG, false);
+    }
+
+    /**
+     * Test profiling request with no issues makes it to perfetto kick off and fails because we're
+     * using the wrong context in these tests.
+     */
+    @Test
+    public void testRequestProfiling_Allowed_PerfettoPermissions_Fails() {
+        // Bypass traces running check, we're not testing that here.
+        doReturn(false).when(mProfilingService).areAnyTracesRunning();
+
+        // Register callback.
+        ProfilingResultCallback callback = new ProfilingResultCallback();
+        mProfilingService.registerResultsCallback(callback);
+
+        // Kick off request.
+        mProfilingService.requestProfiling(ProfilingTestUtils.getJavaHeapDumpProfilingRequest(),
+                APP_FILE_PATH, REQUEST_TAG, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+
+        // Perfetto cannot be run from this context, ensure it was attempted and failed permissions.
+        confirmResultCallback(callback, null, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS,
+                ProfilingResult.ERROR_UNKNOWN, REQUEST_TAG, true);
+        assertEquals("Perfetto error", callback.mError);
+    }
+
+    /** Test that checking if any traces are running works when trace is running. */
+    @Test
+    public void testAreAnyTracesRunning_True() {
+        // Ensure no active tracing sessions tracked.
+        mProfilingService.mTracingSessions.clear();
+        assertFalse(mProfilingService.areAnyTracesRunning());
+
+        // Create a tracing session.
+        TracingSession tracingSession = new TracingSession(null, APP_FILE_PATH, 123,
+                APP_PACKAGE_NAME, REQUEST_TAG, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+
+        // Mock tracing session to be running.
+        doReturn(true).when(mActiveTrace).isAlive();
+
+        // Add trace to session and session to ProfilingService tracked sessions.
+        tracingSession.setActiveTrace(mActiveTrace);
+        mProfilingService.mTracingSessions.put(
+                (new UUID(KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS)).toString(), tracingSession);
+
+        // Confirm check returns that a trace is running.
+        assertTrue(mProfilingService.areAnyTracesRunning());
+    }
+
+    /** Test that checking if any traces are running works when trace is not running. */
+    @Test
+    public void testAreAnyTracesRunning_False() {
+        mProfilingService.mTracingSessions.clear();
+        assertFalse(mProfilingService.areAnyTracesRunning());
+
+        TracingSession tracingSession = new TracingSession(null, APP_FILE_PATH, 123,
+                APP_PACKAGE_NAME, REQUEST_TAG, KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+        mProfilingService.mTracingSessions.put(
+                (new UUID(KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS)).toString(), tracingSession);
+        assertFalse(mProfilingService.areAnyTracesRunning());
+    }
+
+    /** Test that request cancel trace does nothing if no trace is running. */
+    @Test
+    public void testRequestCancel_NotRunning() {
+        // Ensure no active tracing sessions tracked.
+        mProfilingService.mTracingSessions.clear();
+        assertFalse(mProfilingService.areAnyTracesRunning());
+
+        // Register callback.
+        ProfilingResultCallback callback = new ProfilingResultCallback();
+        mProfilingService.registerResultsCallback(callback);
+
+        // Request cancellation.
+        mProfilingService.requestCancel(KEY_MOST_SIG_BITS, KEY_LEAST_SIG_BITS);
+
+        // Confirm callback was not triggerd with a result because there was no trace to stop.
+        assertFalse(callback.mResultSent);
+    }
+
+    /** Confirm that all fields returned by callback match expectation. */
+    private void confirmResultCallback(ProfilingResultCallback callback, String resultFile,
+            long keyMostSigBits, long keyLeastSigBits, int status, String tag,
+            boolean errorExpected) {
+        assertEquals(resultFile, callback.mResultFile);
+        assertEquals(keyMostSigBits, callback.mKeyMostSigBits);
+        assertEquals(keyLeastSigBits, callback.mKeyLeastSigBits);
+        assertEquals(status, callback.mStatus);
+        assertEquals(tag, callback.mTag);
+        if (errorExpected) {
+            assertNotNull(callback.mError);
+        } else {
+            assertNull(callback.mError);
+        }
+    }
+
+    public static class ProfilingResultCallback extends IProfilingResultCallback.Stub {
+        boolean mResultSent = false;
+        boolean mFileRequested = false;
+        public String mResultFile;
+        public long mKeyMostSigBits;
+        public long mKeyLeastSigBits;
+        public int mStatus;
+        public String mTag;
+        public String mError;
+        @Override
+        public void sendResult(String resultFile, long keyMostSigBits,
+                long keyLeastSigBits, int status, String tag, String error) {
+            mResultSent = true;
+            mResultFile = resultFile;
+            mKeyMostSigBits = keyMostSigBits;
+            mKeyLeastSigBits = keyLeastSigBits;
+            mStatus = status;
+            mTag = tag;
+            mError = error;
+        }
+        @Override
+        public ParcelFileDescriptor generateFile(String filePathAbsolute, String fileName) {
+            mFileRequested = true;
+            return null;
+        }
     }
 }
 
diff --git a/tests/cts/src/android/profiling/cts/ProfilingTestUtils.java b/tests/cts/src/android/profiling/cts/ProfilingTestUtils.java
index e6297f0..e17e2d4 100644
--- a/tests/cts/src/android/profiling/cts/ProfilingTestUtils.java
+++ b/tests/cts/src/android/profiling/cts/ProfilingTestUtils.java
@@ -21,7 +21,6 @@
 import android.os.OutcomeReceiver;
 import android.os.ParcelUuid;
 import android.os.ProfilingRequest;
-import android.os.ProfilingRequest.SystemTrace;
 import android.os.ProfilingResult;
 import android.os.RemoteException;
 import android.util.Log;
@@ -38,11 +37,59 @@
     }
 
     public static byte[] getSystemTraceProfilingRequest() {
-        SystemTrace systemTrace = ProfilingRequest.SystemTrace.newBuilder().build();
-        ProfilingRequest.Config profilingRequestConfig =
-                ProfilingRequest.Config.newBuilder().setSystemTrace(systemTrace).build();
-        ProfilingRequest profilingRequest =
-                ProfilingRequest.newBuilder().setConfig(profilingRequestConfig).build();
-        return profilingRequest.toByteArray();
+        // Create system trace proto object.
+        ProfilingRequest.SystemTrace systemTrace
+                = ProfilingRequest.SystemTrace.newBuilder().build();
+
+        // Create config proto object with only system trace type set.
+        ProfilingRequest.Config config
+                = ProfilingRequest.Config.newBuilder().setSystemTrace(systemTrace).build();
+
+        // Create profiling request object with config and convert to byte array.
+        return getProfilingRequestFromConfig(config);
+    }
+
+    public static byte[] getJavaHeapDumpProfilingRequest() {
+        // Create jave heap dump proto object.
+        ProfilingRequest.JavaHeapDump javaHeapDump
+                = ProfilingRequest.JavaHeapDump.newBuilder().build();
+
+        // Create config proto object with only java heap dump type set.
+        ProfilingRequest.Config config
+                = ProfilingRequest.Config.newBuilder().setJavaHeapDump(javaHeapDump).build();
+
+        // Create profiling request object with config and convert to byte array.
+        return getProfilingRequestFromConfig(config);
+    }
+
+    public static byte[] getHeapProfileProfilingRequest() {
+        // Create heap profile proto object.
+        ProfilingRequest.HeapProfile heapProfile
+                = ProfilingRequest.HeapProfile.newBuilder().build();
+
+
+        // Create config proto object with only heap profile type set.
+        ProfilingRequest.Config config
+                = ProfilingRequest.Config.newBuilder().setHeapProfile(heapProfile).build();
+
+        // Create profiling request object with config and convert to byte array.
+        return getProfilingRequestFromConfig(config);
+    }
+
+    public static byte[] getStackSamplingProfilingRequest() {
+        // Create stack sampling proto object.
+        ProfilingRequest.StackSampling stackSampling
+                = ProfilingRequest.StackSampling.newBuilder().build();
+
+        // Create config proto object with only stack sampling type set.
+        ProfilingRequest.Config config
+                = ProfilingRequest.Config.newBuilder().setStackSampling(stackSampling).build();
+
+        // Create profiling request object with config and convert to byte array.
+        return getProfilingRequestFromConfig(config);
+    }
+
+    private static byte[] getProfilingRequestFromConfig(ProfilingRequest.Config config) {
+        return ProfilingRequest.newBuilder().setConfig(config).build().toByteArray();
     }
 }
\ No newline at end of file