Merge change 4111 into donut

* changes:
  Move package installation logic from ADT to ddmlib.
This commit is contained in:
Android (Google) Code Review
2009-06-17 15:03:50 -07:00
4 changed files with 234 additions and 137 deletions

View File

@@ -21,12 +21,9 @@ import com.android.ddmlib.Client;
import com.android.ddmlib.ClientData;
import com.android.ddmlib.IDevice;
import com.android.ddmlib.Log;
import com.android.ddmlib.MultiLineReceiver;
import com.android.ddmlib.SyncService;
import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener;
import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener;
import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
import com.android.ddmlib.SyncService.SyncResult;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration.TargetMode;
import com.android.ide.eclipse.adt.internal.launch.DelayedLaunchInfo.InstallRetryMode;
@@ -74,8 +71,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Controls the launch of Android application either on a device or on the
@@ -134,47 +129,6 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
/** static instance for singleton */
private static AndroidLaunchController sThis = new AndroidLaunchController();
/**
* Output receiver for "pm install package.apk" command line.
*/
private static final class InstallReceiver extends MultiLineReceiver {
private static final String SUCCESS_OUTPUT = "Success"; //$NON-NLS-1$
private static final Pattern FAILURE_PATTERN = Pattern.compile("Failure\\s+\\[(.*)\\]"); //$NON-NLS-1$
private String mSuccess = null;
public InstallReceiver() {
}
@Override
public void processNewLines(String[] lines) {
for (String line : lines) {
if (line.length() > 0) {
if (line.startsWith(SUCCESS_OUTPUT)) {
mSuccess = null;
} else {
Matcher m = FAILURE_PATTERN.matcher(line);
if (m.matches()) {
mSuccess = m.group(1);
}
}
}
}
}
public boolean isCancelled() {
return false;
}
public String getSuccess() {
return mSuccess;
}
}
/** private constructor to enforce singleton */
private AndroidLaunchController() {
AndroidDebugBridge.addDebugBridgeChangeListener(this);
@@ -847,70 +801,29 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
* @return true if the install succeeded.
*/
private boolean doSyncApp(DelayedLaunchInfo launchInfo, IDevice device) {
IPath path = launchInfo.getPackageFile().getLocation();
String fileName = path.lastSegment();
try {
SyncService sync = device.getSyncService();
if (sync != null) {
IPath path = launchInfo.getPackageFile().getLocation();
String message = String.format("Uploading %1$s onto device '%2$s'",
path.lastSegment(), device.getSerialNumber());
AdtPlugin.printToConsole(launchInfo.getProject(), message);
String message = String.format("Uploading %1$s onto device '%2$s'",
fileName, device.getSerialNumber());
AdtPlugin.printToConsole(launchInfo.getProject(), message);
String osLocalPath = path.toOSString();
String apkName = launchInfo.getPackageFile().getName();
String remotePath = "/data/local/tmp/" + apkName; //$NON-NLS-1$
String remotePackagePath = device.syncPackageToDevice(path.toOSString());
boolean installResult = installPackage(launchInfo, remotePackagePath, device);
device.removeRemotePackage(remotePackagePath);
SyncResult result = sync.pushFile(osLocalPath, remotePath,
SyncService.getNullProgressMonitor());
if (result.getCode() != SyncService.RESULT_OK) {
String msg = String.format("Failed to upload %1$s on '%2$s': %3$s",
apkName, device.getSerialNumber(), result.getMessage());
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
return false;
}
// Now that the package is uploaded, we can install it properly.
// This will check that there isn't another apk declaring the same package, or
// that another install used a different key.
boolean installResult = installPackage(launchInfo, remotePath, device);
// now we delete the app we sync'ed
try {
device.executeShellCommand("rm " + remotePath, new MultiLineReceiver() { //$NON-NLS-1$
@Override
public void processNewLines(String[] lines) {
// pass
}
public boolean isCancelled() {
return false;
}
});
} catch (IOException e) {
AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
"Failed to delete temporary package: %1$s", e.getMessage()));
return false;
}
// if the installation succeeded, we register it.
if (installResult) {
ApkInstallManager.getInstance().registerInstallation(
launchInfo.getProject(), device);
}
return installResult;
} else {
String msg = String.format(
"Failed to upload %1$s on device '%2$s': Unable to open sync connection!",
launchInfo.getPackageFile().getName(), device.getSerialNumber());
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
// if the installation succeeded, we register it.
if (installResult) {
ApkInstallManager.getInstance().registerInstallation(
launchInfo.getProject(), device);
}
} catch (IOException e) {
String msg = String.format(
"Failed to upload %1$s on device '%2$s': Unable to open sync connection!",
launchInfo.getPackageFile().getName(), device.getSerialNumber());
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg, e.getMessage());
return installResult;
}
catch (IOException e) {
String msg = String.format("Failed to upload %1$s on device '%2$s'", fileName,
device.getSerialNumber());
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg, e);
}
return false;
}
@@ -988,22 +901,19 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
return dependencies;
}
/**
* Installs the application package that was pushed to a temporary location on the device.
* Installs the application package on the device, and handles return result
* @param launchInfo The launch information
* @param remotePath The remote path of the package.
* @param device The device on which the launch is done.
*/
private boolean installPackage(DelayedLaunchInfo launchInfo, final String remotePath,
final IDevice device) {
String message = String.format("Installing %1$s...", launchInfo.getPackageFile().getName());
AdtPlugin.printToConsole(launchInfo.getProject(), message);
try {
String result = doInstall(launchInfo, remotePath, device, false /* reinstall */);
// try a reinstall first, because the most common case is the app is already installed
String result = doInstall(launchInfo, remotePath, device, true /* reinstall */);
/* For now we force to retry the install (after uninstalling) because there's no
* other way around it: adb install does not want to update a package w/o uninstalling
@@ -1012,7 +922,10 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
return checkInstallResult(result, device, launchInfo, remotePath,
InstallRetryMode.ALWAYS);
} catch (IOException e) {
// do nothing, we'll return false
String msg = String.format(
"Failed to install %1$s on device '%2$s!",
launchInfo.getPackageFile().getName(), device.getSerialNumber());
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg, e.getMessage());
}
return false;
@@ -1033,7 +946,9 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
if (result == null) {
AdtPlugin.printToConsole(launchInfo.getProject(), "Success!");
return true;
} else if (result.equals("INSTALL_FAILED_ALREADY_EXISTS")) { //$NON-NLS-1$
}
else if (result.equals("INSTALL_FAILED_ALREADY_EXISTS")) { //$NON-NLS-1$
// this should never happen, since reinstall mode is used on the first attempt
if (retryMode == InstallRetryMode.PROMPT) {
boolean prompt = AdtPlugin.displayPrompt("Application Install",
"A previous installation needs to be uninstalled before the new package can be installed.\nDo you want to uninstall?");
@@ -1067,11 +982,10 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
AdtPlugin.printToConsole(launchInfo.getProject(),
"Application already exists. Attempting to re-install instead...");
String res = doInstall(launchInfo, remotePath, device, true /* reinstall */);
String res = doInstall(launchInfo, remotePath, device, true /* reinstall */ );
return checkInstallResult(res, device, launchInfo, remotePath,
InstallRetryMode.NEVER);
}
AdtPlugin.printErrorToConsole(launchInfo.getProject(),
"Installation error! The package already exists.");
} else if (result.equals("INSTALL_FAILED_INVALID_APK")) { //$NON-NLS-1$
@@ -1110,18 +1024,14 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
*/
@SuppressWarnings("unused")
private String doUninstall(IDevice device, DelayedLaunchInfo launchInfo) throws IOException {
InstallReceiver receiver = new InstallReceiver();
try {
device.executeShellCommand("pm uninstall " + launchInfo.getPackageName(), //$NON-NLS-1$
receiver);
return device.uninstallPackage(launchInfo.getPackageName());
} catch (IOException e) {
String msg = String.format(
"Failed to uninstall %1$s: %2$s", launchInfo.getPackageName(), e.getMessage());
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
throw e;
}
return receiver.getSuccess();
}
/**
@@ -1136,22 +1046,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
*/
private String doInstall(DelayedLaunchInfo launchInfo, final String remotePath,
final IDevice device, boolean reinstall) throws IOException {
InstallReceiver receiver = new InstallReceiver();
try {
String cmd = String.format(
reinstall ? "pm install -r \"%1$s\"" : "pm install \"%1$s\"", //$NON-NLS-1$ //$NON-NLS-2$
remotePath); //$NON-NLS-1$ //$NON-NLS-2$
device.executeShellCommand(cmd, receiver);
} catch (IOException e) {
String msg = String.format(
"Failed to install %1$s on device '%2$s': %3$s",
launchInfo.getPackageFile().getName(), device.getSerialNumber(),
e.getMessage());
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
throw e;
}
return receiver.getSuccess();
return device.installRemotePackage(remotePath, reinstall);
}
/**