diff options
author | Siva Velusamy <vsiva@google.com> | 2012-06-14 10:23:21 -0700 |
---|---|---|
committer | Siva Velusamy <vsiva@google.com> | 2012-06-14 14:41:11 -0700 |
commit | 402265da9bd88a9b1a0751fda7ed2f87414f5cd7 (patch) | |
tree | 9f800d0fedffe1f7fef6fdad00841a45bb7a2e9a | |
parent | d8c3696b3a4987c9733b98ad75ddaf5b4287dd2e (diff) | |
download | sdk-402265da9bd88a9b1a0751fda7ed2f87414f5cd7.zip sdk-402265da9bd88a9b1a0751fda7ed2f87414f5cd7.tar.gz sdk-402265da9bd88a9b1a0751fda7ed2f87414f5cd7.tar.bz2 |
gltrace: cleanup collect trace flow
This CL improves the initial flow to obtain the trace options
from the user and launch the application in trace mode.
- A separate text box is provided if a non-default activity
should be launched for tracing.
- If that application to trace is already running, it needs
to be killed before starting it in trace mode. The tracer
will now wait (upto a timeout value) until it detects that
the application was killed before launching it in trace mode.
- Similarly, the tracer waits until it knows that the app
has launched before attempting to connect to it.
- Checks if device is at API level 16.
Change-Id: Iea5be6d76b6e78ea68a05b893aef993099363555
3 files changed, 132 insertions, 27 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java index 1085f3f..9da6c27 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/CollectTraceAction.java @@ -24,6 +24,7 @@ import com.android.ddmlib.IDevice.DeviceUnixSocketNamespace; import com.android.ddmlib.IShellOutputReceiver; import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.TimeoutException; +import com.google.common.util.concurrent.SimpleTimeLimiter; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.MessageDialog; @@ -40,7 +41,9 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.Socket; +import java.util.concurrent.Callable; import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; public class CollectTraceAction implements IWorkbenchWindowActionDelegate { /** Abstract Unix Domain Socket Name used by the gltrace device code. */ @@ -52,6 +55,14 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { /** Activity name to use for a system activity that has already been launched. */ private static final String SYSTEM_APP = "system"; //$NON-NLS-1$ + /** Time to wait for the application to launch (seconds) */ + private static final int LAUNCH_TIMEOUT = 5; + + /** Time to wait for the application to die (seconds) */ + private static final int KILL_TIMEOUT = 5; + + private static final int MIN_API_LEVEL = 16; + @Override public void run(IAction action) { connectToDevice(); @@ -79,6 +90,21 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { TraceOptions traceOptions = dlg.getTraceOptions(); IDevice device = getDevice(traceOptions.device); + String apiLevelString = device.getProperty(IDevice.PROP_BUILD_API_LEVEL); + int apiLevel; + try { + apiLevel = Integer.parseInt(apiLevelString); + } catch (NumberFormatException e) { + apiLevel = MIN_API_LEVEL; + } + if (apiLevel < MIN_API_LEVEL) { + MessageDialog.openError(shell, "GL Trace", + String.format("OpenGL Tracing is only supported on devices at API Level %1$d." + + "The selected device '%2$s' provides API level %3$s.", + MIN_API_LEVEL, traceOptions.device, apiLevelString)); + return; + } + try { setupForwarding(device, LOCAL_FORWARDED_PORT); } catch (Exception e) { @@ -87,8 +113,8 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { } try { - if (!SYSTEM_APP.equals(traceOptions.activityToTrace)) { - startActivity(device, traceOptions.activityToTrace); + if (!SYSTEM_APP.equals(traceOptions.appToTrace)) { + startActivity(device, traceOptions.appToTrace, traceOptions.activityToTrace); } } catch (Exception e) { MessageDialog.openError(shell, "Setup GL Trace", @@ -96,13 +122,6 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { return; } - try { - // wait a couple of seconds for the application to launch on the device - Thread.sleep(2000); - } catch (InterruptedException e) { - // can't be interrupted - } - // if everything went well, the app should now be waiting for the gl debugger // to connect startTracing(shell, traceOptions, LOCAL_FORWARDED_PORT); @@ -171,21 +190,26 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { } } - private void startActivity(IDevice device, String appName) + private void startActivity(IDevice device, String appPackage, String activity) throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException, InterruptedException { - killApp(device, appName); // kill app if it is already running + killApp(device, appPackage); // kill app if it is already running + waitUntilAppKilled(device, appPackage, KILL_TIMEOUT); + String activityPath = appPackage; + if (!activity.isEmpty()) { + activityPath = String.format("%s/.%s", appPackage, activity); //$NON-NLS-1$ + } String startAppCmd = String.format( "am start --opengl-trace %s -a android.intent.action.MAIN -c android.intent.category.LAUNCHER", //$NON-NLS-1$ - appName); + activityPath); Semaphore launchCompletionSempahore = new Semaphore(0); StartActivityOutputReceiver receiver = new StartActivityOutputReceiver( launchCompletionSempahore); device.executeShellCommand(startAppCmd, receiver); - // wait until shell finishes launch + // wait until shell finishes launch command launchCompletionSempahore.acquire(); // throw exception if there was an error during launch @@ -193,6 +217,9 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { if (output.contains("Error")) { //$NON-NLS-1$ throw new RuntimeException(output); } + + // wait until the app itself has been launched + waitUntilAppLaunched(device, appPackage, LAUNCH_TIMEOUT); } private void killApp(IDevice device, String appName) { @@ -202,6 +229,51 @@ public class CollectTraceAction implements IWorkbenchWindowActionDelegate { } } + private void waitUntilAppLaunched(final IDevice device, final String appName, int timeout) { + Callable<Boolean> c = new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + Client client; + do { + client = device.getClient(appName); + } while (client == null); + + return Boolean.TRUE; + } + }; + try { + new SimpleTimeLimiter().callWithTimeout(c, timeout, TimeUnit.SECONDS, true); + } catch (Exception e) { + throw new RuntimeException("Timed out waiting for application to launch."); + } + + // once the app has launched, wait an additional couple of seconds + // for it to start up + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + // ignore + } + } + + private void waitUntilAppKilled(final IDevice device, final String appName, int timeout) { + Callable<Boolean> c = new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + Client client; + while ((client = device.getClient(appName)) != null) { + client.kill(); + } + return Boolean.TRUE; + } + }; + try { + new SimpleTimeLimiter().callWithTimeout(c, timeout, TimeUnit.SECONDS, true); + } catch (Exception e) { + throw new RuntimeException("Timed out waiting for running application to die."); + } + } + private void setupForwarding(IDevice device, int i) throws TimeoutException, AdbCommandRejectedException, IOException { device.createForward(i, GLTRACE_UDS, DeviceUnixSocketNamespace.ABSTRACT); diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java index ef94452..43db5d8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/GLTraceOptionsDialog.java @@ -52,9 +52,10 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { private static final String TITLE = "OpenGL ES Trace Options"; private static final String DEFAULT_MESSAGE = "Provide the application and activity to be traced."; - private static final String PREF_APPNAME = "gl.trace.appname"; //$NON-NLS-1$ - private static final String PREF_TRACEFILE = "gl.trace.destfile"; //$NON-NLS-1$ - private static final String PREF_DEVICE = "gl.trace.device"; //$NON-NLS-1$ + private static final String PREF_APP_PACKAGE = "gl.trace.apppackage"; //$NON-NLS-1$ + private static final String PREF_ACTIVITY = "gl.trace.activity"; //$NON-NLS-1$ + private static final String PREF_TRACEFILE = "gl.trace.destfile"; //$NON-NLS-1$ + private static final String PREF_DEVICE = "gl.trace.device"; //$NON-NLS-1$ private String mLastUsedDevice; private static String sSaveToFolder = System.getProperty("user.home"); //$NON-NLS-1$ @@ -62,10 +63,12 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { private Button mOkButton; private Combo mDeviceCombo; + private Text mAppPackageToTraceText; private Text mActivityToTraceText; private Text mTraceFilePathText; private String mSelectedDevice = ""; + private String mAppPackageToTrace = ""; private String mActivityToTrace = ""; private String mTraceFilePath = ""; @@ -93,10 +96,13 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { mDevices = AndroidDebugBridge.getBridge().getDevices(); createDeviceDropdown(c, mDevices); - createLabel(c, "Activity:"); - createAppToTraceText(c, "e.g. com.example.package/.ActivityName"); + createLabel(c, "Application Package:"); + createAppToTraceText(c, "e.g. com.example.package"); - createLabel(c, "Capture Image:"); + createLabel(c, "Activity to launch:"); + createActivityToTraceText(c, "Leave blank to launch default activity"); + + createLabel(c, "Data Collection Options:"); createCaptureImageOptions(c); createSeparator(c); @@ -207,6 +213,23 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { } private Text createAppToTraceText(Composite parent, String defaultMessage) { + mAppPackageToTraceText = new Text(parent, SWT.BORDER); + mAppPackageToTraceText.setMessage(defaultMessage); + mAppPackageToTraceText.setText(mAppPackageToTrace); + + mAppPackageToTraceText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + mAppPackageToTraceText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + validateAndSetMessage(); + } + }); + + return mActivityToTraceText; + } + + private Text createActivityToTraceText(Composite parent, String defaultMessage) { mActivityToTraceText = new Text(parent, SWT.BORDER); mActivityToTraceText.setMessage(defaultMessage); mActivityToTraceText.setText(mActivityToTrace); @@ -277,7 +300,7 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { return new DialogStatus(false, "No connected devices."); } - if (mActivityToTraceText.getText().trim().length() == 0) { + if (mAppPackageToTraceText.getText().trim().isEmpty()) { return new DialogStatus(false, "Provide an application name"); } @@ -297,8 +320,12 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { @Override protected void okPressed() { - mActivityToTrace = mActivityToTraceText.getText(); - mTraceFilePath = mTraceFilePathText.getText(); + mAppPackageToTrace = mAppPackageToTraceText.getText().trim(); + mActivityToTrace = mActivityToTraceText.getText().trim(); + if (mActivityToTrace.startsWith(".")) { //$NON-NLS-1$ + mActivityToTrace = mActivityToTrace.substring(1); + } + mTraceFilePath = mTraceFilePathText.getText().trim(); mSelectedDevice = mDeviceCombo.getText(); savePreferences(); @@ -308,7 +335,8 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { private void savePreferences() { IEclipsePreferences prefs = new InstanceScope().getNode(GlTracePlugin.PLUGIN_ID); - prefs.put(PREF_APPNAME, mActivityToTrace); + prefs.put(PREF_APP_PACKAGE, mAppPackageToTrace); + prefs.put(PREF_ACTIVITY, mActivityToTrace); prefs.put(PREF_TRACEFILE, mTraceFilePath); prefs.put(PREF_DEVICE, mSelectedDevice); try { @@ -320,13 +348,14 @@ public class GLTraceOptionsDialog extends TitleAreaDialog { private void loadPreferences() { IEclipsePreferences prefs = new InstanceScope().getNode(GlTracePlugin.PLUGIN_ID); - mActivityToTrace = prefs.get(PREF_APPNAME, ""); + mAppPackageToTrace = prefs.get(PREF_APP_PACKAGE, ""); + mActivityToTrace = prefs.get(PREF_ACTIVITY, ""); mTraceFilePath = prefs.get(PREF_TRACEFILE, ""); mLastUsedDevice = prefs.get(PREF_DEVICE, ""); } public TraceOptions getTraceOptions() { - return new TraceOptions(mSelectedDevice, mActivityToTrace.trim(), mTraceFilePath, - mCollectFbOnEglSwap, mCollectFbOnGlDraw, mCollectTextureData); + return new TraceOptions(mSelectedDevice, mAppPackageToTrace, mActivityToTrace, + mTraceFilePath, mCollectFbOnEglSwap, mCollectFbOnGlDraw, mCollectTextureData); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java index d67d167..e7ad17e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java +++ b/eclipse/plugins/com.android.ide.eclipse.gldebugger/src/com/android/ide/eclipse/gltrace/TraceOptions.java @@ -20,6 +20,9 @@ public class TraceOptions { /** Device on which the application should be run. */ public final String device; + /** Application to trace. */ + public final String appToTrace; + /** Activity to trace. */ public final String activityToTrace; @@ -35,9 +38,10 @@ public class TraceOptions { /** Flag indicating whether texture data should be captured on glTexImage*() */ public final boolean collectTextureData; - public TraceOptions(String device, String activity, String destinationPath, + public TraceOptions(String device, String appPackage, String activity, String destinationPath, boolean collectFbOnEglSwap, boolean collectFbOnGlDraw, boolean collectTextureData) { this.device = device; + this.appToTrace = appPackage; this.activityToTrace = activity; this.traceDestination = destinationPath; this.collectFbOnEglSwap = collectFbOnEglSwap; |