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