From 05e6b1fc1f328fe49603ac741e78d314466bd442 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Thu, 2 Apr 2009 15:36:04 -0700 Subject: [PATCH] AI 144320: ADT: Fix debugger launch connection when debugging Android JUnit BUG=1753089 Automated import of CL 144320 --- .../adt/launch/AndroidLaunchController.java | 12 ++++-- .../ide/eclipse/adt/launch/DelayedLaunchInfo.java | 20 ++++++++- .../eclipse/adt/launch/LaunchConfigDelegate.java | 7 ++-- .../adt/launch/junit/AndroidJUnitLaunchAction.java | 1 - .../junit/AndroidJUnitLaunchConfigDelegate.java | 41 ++++++++++++++---- .../junit/AndroidJUnitLaunchConfigurationTab.java | 2 +- .../junit/InstrumentationRunnerValidator.java | 19 +++++---- .../common/project/AndroidManifestParser.java | 49 ++++++++++++++++++---- .../common/project/AndroidManifestParserTest.java | 16 ++++--- 9 files changed, 124 insertions(+), 43 deletions(-) diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java index b6c7640c7..655c038e1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java @@ -314,6 +314,8 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener * defined by ILaunchManager - RUN_MODE or * DEBUG_MODE. * @param apk the resource to the apk to launch. + * @param packageName the Android package name of the app + * @param debugPackageName the Android package name to debug * @param debuggable the debuggable value of the app, or null if not set. * @param requiredApiVersionNumber the api version required by the app, or * {@link AndroidManifestParser#INVALID_MIN_SDK} if none. @@ -322,7 +324,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener * @param launch the launch object */ public void launch(final IProject project, String mode, IFile apk, - String packageName, Boolean debuggable, int requiredApiVersionNumber, + String packageName, String debugPackageName, Boolean debuggable, int requiredApiVersionNumber, final IAndroidLaunchAction launchAction, final AndroidLaunchConfiguration config, final AndroidLaunch launch, IProgressMonitor monitor) { @@ -331,7 +333,8 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener // create the launch info final DelayedLaunchInfo launchInfo = new DelayedLaunchInfo(project, packageName, - launchAction, apk, debuggable, requiredApiVersionNumber, launch, monitor); + debugPackageName, launchAction, apk, debuggable, requiredApiVersionNumber, launch, + monitor); // set the debug mode launchInfo.setDebugMode(mode.equals(ILaunchManager.DEBUG_MODE)); @@ -922,6 +925,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener DelayedLaunchInfo delayedLaunchInfo = new DelayedLaunchInfo( androidProject.getProject(), manifestParser.getPackage(), + manifestParser.getPackage(), launchInfo.getLaunchAction(), apk, manifestParser.getDebuggable(), @@ -1524,14 +1528,14 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener for (int i = 0; i < mWaitingForDebuggerApplications.size(); ) { final DelayedLaunchInfo launchInfo = mWaitingForDebuggerApplications.get(i); if (client.getDevice() == launchInfo.getDevice() && - applicationName.equals(launchInfo.getPackageName())) { + applicationName.equals(launchInfo.getDebugPackageName())) { // this is a match. We remove the launch info from the list mWaitingForDebuggerApplications.remove(i); // and connect the debugger. String msg = String.format( "Attempting to connect debugger to '%1$s' on port %2$d", - launchInfo.getPackageName(), client.getDebuggerListenPort()); + launchInfo.getDebugPackageName(), client.getDebuggerListenPort()); AdtPlugin.printToConsole(launchInfo.getProject(), msg); new Thread("Debugger Connection") { //$NON-NLS-1$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java index 7dae56d00..f3bd28a07 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java @@ -44,6 +44,9 @@ public final class DelayedLaunchInfo { /** Package name */ private final String mPackageName; + + /** Debug package name */ + private final String mDebugPackageName; /** IFile to the package (.apk) file */ private final IFile mPackageFile; @@ -79,7 +82,8 @@ public final class DelayedLaunchInfo { * Basic constructor with activity and package info. * * @param project the eclipse project that corresponds to Android app - * @param packageName package name of Android app + * @param packageName package name of Android app + * @param debugPackageName the package name of the Andriod app to debug * @param launchAction action to perform after app install * @param pack IFile to the package (.apk) file * @param debuggable debuggable attribute of the app's manifest file. @@ -88,11 +92,12 @@ public final class DelayedLaunchInfo { * @param launch the launch object * @param monitor progress monitor for launch */ - public DelayedLaunchInfo(IProject project, String packageName, + public DelayedLaunchInfo(IProject project, String packageName, String debugPackageName, IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable, int requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) { mProject = project; mPackageName = packageName; + mDebugPackageName = debugPackageName; mPackageFile = pack; mLaunchAction = launchAction; mLaunch = launch; @@ -130,6 +135,17 @@ public final class DelayedLaunchInfo { } /** + * Returns the Android app process name that the debugger should connect to. Typically this is + * the same value as {@link getPackageName} + */ + public String getDebugPackageName() { + if (mDebugPackageName == null) { + return getPackageName(); + } + return mDebugPackageName; + } + + /** * @return the application package file */ public IFile getPackageFile() { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java index d057ac709..9f12b16e4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java @@ -306,9 +306,10 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate { // everything seems fine, we ask the launch controller to handle // the rest - controller.launch(project, mode, applicationPackage, manifestParser.getPackage(), - manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(), - launchAction, config, androidLaunch, monitor); + controller.launch(project, mode, applicationPackage,manifestParser.getPackage(), + manifestParser.getPackage(), manifestParser.getDebuggable(), + manifestParser.getApiLevelRequirement(), launchAction, config, androidLaunch, + monitor); } @Override diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java index 9bcc63d06..24ebe21c0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java @@ -63,7 +63,6 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { try { mLaunchInfo.setDebugMode(info.isDebugMode()); mLaunchInfo.setDevice(info.getDevice()); - mLaunchInfo.setLaunch(info.getLaunch()); JUnitLaunchDelegate junitDelegate = new JUnitLaunchDelegate(mLaunchInfo); final String mode = info.isDebugMode() ? ILaunchManager.DEBUG_MODE : ILaunchManager.RUN_MODE; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java index 543daf06f..19067921b 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java @@ -25,6 +25,7 @@ import com.android.ide.eclipse.adt.launch.LaunchConfigDelegate; import com.android.ide.eclipse.adt.launch.junit.runtime.AndroidJUnitLaunchInfo; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.AndroidManifestParser; +import com.android.ide.eclipse.common.project.AndroidManifestParser.Instrumentation; import com.android.ide.eclipse.common.project.BaseProjectHelper; import org.eclipse.core.resources.IFile; @@ -60,7 +61,6 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { AndroidLaunchConfiguration config, AndroidLaunchController controller, IFile applicationPackage, AndroidManifestParser manifestParser) { - String appPackage = manifestParser.getPackage(); String runner = getRunner(project, configuration, manifestParser); if (runner == null) { AdtPlugin.displayError("Android Launch", @@ -68,19 +68,46 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { androidLaunch.stopLaunch(); return; } - AndroidJUnitLaunchInfo junitLaunchInfo = new AndroidJUnitLaunchInfo(project, appPackage, - runner); + // get the target app's package + String targetAppPackage = getTargetPackage(manifestParser, runner); + if (targetAppPackage == null) { + AdtPlugin.displayError("Android Launch", + String.format("A target package for instrumention test runner %1$s could not be found!", + runner)); + androidLaunch.stopLaunch(); + return; + } + String testAppPackage = manifestParser.getPackage(); + AndroidJUnitLaunchInfo junitLaunchInfo = new AndroidJUnitLaunchInfo(project, + testAppPackage, runner); junitLaunchInfo.setTestClass(getTestClass(configuration)); junitLaunchInfo.setTestPackage(getTestPackage(configuration)); junitLaunchInfo.setTestMethod(getTestMethod(configuration)); - + junitLaunchInfo.setLaunch(androidLaunch); IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(junitLaunchInfo); - - controller.launch(project, mode, applicationPackage, manifestParser.getPackage(), + + controller.launch(project, mode, applicationPackage, testAppPackage, targetAppPackage, manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(), junitLaunch, config, androidLaunch, monitor); } - + + /** + * Get the target Android application's package for the given instrumentation runner, or + * null if it could not be found. + * + * @param manifestParser the {@link AndroidManifestParser} for the test project + * @param runner the instrumentation runner class name + * @return the target package or null + */ + private String getTargetPackage(AndroidManifestParser manifestParser, String runner) { + for (Instrumentation instr : manifestParser.getInstrumentations()) { + if (instr.getName().equals(runner)) { + return instr.getTargetPackage(); + } + } + return null; + } + /** * Returns the test package stored in the launch configuration, or null if not * specified. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java index 584d45eb1..34e64e327 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java @@ -955,7 +955,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat try { mInstrValidator = new InstrumentationRunnerValidator(project); mInstrumentations = (mInstrValidator == null ? null : - mInstrValidator.getInstrumentations()); + mInstrValidator.getInstrumentationNames()); if (mInstrumentations != null) { mInstrumentationCombo.removeAll(); for (String instrumentation : mInstrumentations) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java index f22fc7cda..7ebbb0997 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/InstrumentationRunnerValidator.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.launch.junit; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.AndroidManifestParser; +import com.android.ide.eclipse.common.project.AndroidManifestParser.Instrumentation; import com.android.ide.eclipse.common.project.BaseProjectHelper; import org.eclipse.core.resources.IProject; @@ -29,7 +30,7 @@ import org.eclipse.jdt.core.IJavaProject; */ class InstrumentationRunnerValidator { private final IJavaProject mJavaProject; - private String[] mInstrumentations = null; + private String[] mInstrumentationNames = null; private boolean mHasRunnerLibrary = false; static final String INSTRUMENTATION_OK = null; @@ -73,7 +74,11 @@ class InstrumentationRunnerValidator { } private void init(AndroidManifestParser manifestParser) { - mInstrumentations = manifestParser.getInstrumentations(); + Instrumentation[] instrumentations = manifestParser.getInstrumentations(); + mInstrumentationNames = new String[instrumentations.length]; + for (int i = 0; i < instrumentations.length; i++) { + mInstrumentationNames[i] = instrumentations[i].getName(); + } mHasRunnerLibrary = hasTestRunnerLibrary(manifestParser); } @@ -94,13 +99,13 @@ class InstrumentationRunnerValidator { } /** - * Return the set of instrumentations for the Android project. + * Return the set of instrumentation names for the Android project. * * @return nullINSTRUMENTATION_OK if valid, otherwise returns error message */ String validateInstrumentationRunner(String instrumentation) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java index 85ba96839..f853adacb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java @@ -52,6 +52,7 @@ public class AndroidManifestParser { private final static String ATTRIBUTE_PROCESS = "process"; //$NON-NLS-$ private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$ private final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$ + private final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$ private final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$ private final static String NODE_APPLICATION = "application"; //$NON-NLS-1$ private final static String NODE_ACTIVITY = "activity"; //$NON-NLS-1$ @@ -77,6 +78,33 @@ public class AndroidManifestParser { public final static int INVALID_MIN_SDK = -1; /** + * Instrumentation info obtained from manifest + */ + public static class Instrumentation { + private final String mName; + private final String mTargetPackage; + + public Instrumentation(String name, String targetPackage) { + mName = name; + mTargetPackage = targetPackage; + } + + /** + * Returns the fully qualified instrumentation class name + */ + public String getName() { + return mName; + } + + /** + * Returns the Android app package that is the target of this instrumentation + */ + public String getTargetPackage() { + return mTargetPackage; + } + } + + /** * XML error & data handler used when parsing the AndroidManifest.xml file. *

* This serves both as an {@link XmlErrorHandler} to report errors and as a data repository @@ -100,7 +128,8 @@ public class AndroidManifestParser { * the attribute was not present. */ private int mApiLevelRequirement = INVALID_MIN_SDK; /** List of all instrumentations declared by the manifest */ - private final ArrayList mInstrumentations = new ArrayList(); + private final ArrayList mInstrumentations = + new ArrayList(); /** List of all libraries in use declared by the manifest */ private final ArrayList mLibraries = new ArrayList(); @@ -185,11 +214,11 @@ public class AndroidManifestParser { /** * Returns the list of instrumentations found in the manifest. - * @return An array of instrumentation names, or empty if no instrumentations were + * @return An array of {@link Instrumentation}, or empty if no instrumentations were * found. */ - String[] getInstrumentations() { - return mInstrumentations.toArray(new String[mInstrumentations.size()]); + Instrumentation[] getInstrumentations() { + return mInstrumentations.toArray(new Instrumentation[mInstrumentations.size()]); } /** @@ -459,7 +488,9 @@ public class AndroidManifestParser { true /* hasNamespace */); if (instrumentationName != null) { String instrClassName = combinePackageAndClassName(mPackage, instrumentationName); - mInstrumentations.add(instrClassName); + String targetPackage = getAttributeValue(attributes, ATTRIBUTE_TARGET_PACKAGE, + true /* hasNamespace */); + mInstrumentations.add(new Instrumentation(instrClassName, targetPackage)); if (mMarkErrors) { checkClass(instrClassName, AndroidConstants.CLASS_INSTRUMENTATION, true /* testVisibility */); @@ -544,7 +575,7 @@ public class AndroidManifestParser { private final String[] mProcesses; private final Boolean mDebuggable; private final int mApiLevelRequirement; - private final String[] mInstrumentations; + private final Instrumentation[] mInstrumentations; private final String[] mLibraries; static { @@ -819,9 +850,9 @@ public class AndroidManifestParser { /** * Returns the list of instrumentations found in the manifest. - * @return An array of fully qualified class names, or empty if no instrumentations were found. + * @return An array of {@link Instrumentation}, or empty if no instrumentations were found. */ - public String[] getInstrumentations() { + public Instrumentation[] getInstrumentations() { return mInstrumentations; } @@ -851,7 +882,7 @@ public class AndroidManifestParser { */ private AndroidManifestParser(String javaPackage, String[] activities, String launcherActivity, String[] processes, Boolean debuggable, - int apiLevelRequirement, String[] instrumentations, String[] libraries) { + int apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) { mJavaPackage = javaPackage; mActivities = activities; mLauncherActivity = launcherActivity; diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java index 7e8b0af10..2f93e5179 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java @@ -33,7 +33,7 @@ public class AndroidManifestParserTest extends TestCase { private static final String ACTIVITY_NAME = "com.android.testapp.MainActivity"; //$NON-NLS-1$ private static final String LIBRARY_NAME = "android.test.runner"; //$NON-NLS-1$ private static final String INSTRUMENTATION_NAME = "android.test.InstrumentationTestRunner"; //$NON-NLS-1$ - + private static final String INSTRUMENTATION_TARGET = "com.android.AndroidProject"; //$NON-NLS-1$ @Override protected void setUp() throws Exception { super.setUp(); @@ -51,7 +51,10 @@ public class AndroidManifestParserTest extends TestCase { public void testGetInstrumentationInformation() { assertEquals(1, mManifestInstrumentation.getInstrumentations().length); - assertEquals(INSTRUMENTATION_NAME, mManifestTestApp.getInstrumentations()[0]); + assertEquals(INSTRUMENTATION_NAME, + mManifestInstrumentation.getInstrumentations()[0].getName()); + assertEquals(INSTRUMENTATION_TARGET, + mManifestInstrumentation.getInstrumentations()[0].getTargetPackage()); } public void testGetPackage() { @@ -66,17 +69,12 @@ public class AndroidManifestParserTest extends TestCase { public void testGetLauncherActivity() { assertEquals(ACTIVITY_NAME, mManifestTestApp.getLauncherActivity()); } - + public void testGetUsesLibraries() { assertEquals(1, mManifestTestApp.getUsesLibraries().length); assertEquals(LIBRARY_NAME, mManifestTestApp.getUsesLibraries()[0]); } - - public void testGetInstrumentations() { - assertEquals(1, mManifestTestApp.getInstrumentations().length); - assertEquals(INSTRUMENTATION_NAME, mManifestTestApp.getInstrumentations()[0]); - } - + public void testGetPackageName() { assertEquals(PACKAGE_NAME, mManifestTestApp.getPackage()); } -- 2.11.0