Move package installation logic from ADT to ddmlib.
This commit is contained in:
@@ -16,8 +16,10 @@
|
||||
|
||||
package com.android.ddmlib;
|
||||
|
||||
import com.android.ddmlib.SyncService.SyncResult;
|
||||
import com.android.ddmlib.log.LogReceiver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.ArrayList;
|
||||
@@ -25,6 +27,8 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
@@ -50,11 +54,51 @@ final class Device implements IDevice {
|
||||
private final ArrayList<Client> mClients = new ArrayList<Client>();
|
||||
private DeviceMonitor mMonitor;
|
||||
|
||||
private static final String LOG_TAG = "Device";
|
||||
|
||||
/**
|
||||
* Socket for the connection monitoring client connection/disconnection.
|
||||
*/
|
||||
private SocketChannel mSocketChannel;
|
||||
|
||||
/**
|
||||
* 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 mErrorMessage = null;
|
||||
|
||||
public InstallReceiver() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processNewLines(String[] lines) {
|
||||
for (String line : lines) {
|
||||
if (line.length() > 0) {
|
||||
if (line.startsWith(SUCCESS_OUTPUT)) {
|
||||
mErrorMessage = null;
|
||||
} else {
|
||||
Matcher m = FAILURE_PATTERN.matcher(line);
|
||||
if (m.matches()) {
|
||||
mErrorMessage = m.group(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return mErrorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.android.ddmlib.IDevice#getSerialNumber()
|
||||
@@ -373,4 +417,94 @@ final class Device implements IDevice {
|
||||
void addProperty(String label, String value) {
|
||||
mProperties.put(label, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String installPackage(String packageFilePath, boolean reinstall)
|
||||
throws IOException {
|
||||
String remoteFilePath = syncPackageToDevice(packageFilePath);
|
||||
String result = installRemotePackage(remoteFilePath, reinstall);
|
||||
removeRemotePackage(remoteFilePath);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String syncPackageToDevice(String localFilePath)
|
||||
throws IOException {
|
||||
try {
|
||||
String packageFileName = getFileName(localFilePath);
|
||||
String remoteFilePath = String.format("/data/local/tmp/%1$s", packageFileName); //$NON-NLS-1$
|
||||
|
||||
Log.i(packageFileName, String.format("Uploading %1$s onto device '%2$s'",
|
||||
packageFileName, getSerialNumber()));
|
||||
|
||||
SyncService sync = getSyncService();
|
||||
if (sync != null) {
|
||||
String message = String.format("Uploading file onto device '%1$s'",
|
||||
getSerialNumber());
|
||||
Log.i(LOG_TAG, message);
|
||||
SyncResult result = sync.pushFile(localFilePath, remoteFilePath,
|
||||
SyncService.getNullProgressMonitor());
|
||||
|
||||
if (result.getCode() != SyncService.RESULT_OK) {
|
||||
throw new IOException(String.format("Unable to upload file: %1$s",
|
||||
result.getMessage()));
|
||||
}
|
||||
} else {
|
||||
throw new IOException("Unable to open sync connection!");
|
||||
}
|
||||
return remoteFilePath;
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, String.format("Unable to open sync connection! reason: %1$s",
|
||||
e.getMessage()));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to retrieve the file name given a local file path
|
||||
* @param filePath full directory path to file
|
||||
* @return {@link String} file name
|
||||
*/
|
||||
private String getFileName(String filePath) {
|
||||
return new File(filePath).getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String installRemotePackage(String remoteFilePath, boolean reinstall)
|
||||
throws IOException {
|
||||
InstallReceiver receiver = new InstallReceiver();
|
||||
String cmd = String.format(reinstall ? "pm install -r \"%1$s\"" : "pm install \"%1$s\"",
|
||||
remoteFilePath);
|
||||
executeShellCommand(cmd, receiver);
|
||||
return receiver.getErrorMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void removeRemotePackage(String remoteFilePath) throws IOException {
|
||||
// now we delete the app we sync'ed
|
||||
try {
|
||||
executeShellCommand("rm " + remoteFilePath, new NullOutputReceiver());
|
||||
} catch (IOException e) {
|
||||
Log.e(LOG_TAG, String.format("Failed to delete temporary package: %1$s",
|
||||
e.getMessage()));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public String uninstallPackage(String packageName) throws IOException {
|
||||
InstallReceiver receiver = new InstallReceiver();
|
||||
executeShellCommand("pm uninstall " + packageName, receiver);
|
||||
return receiver.getErrorMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ public interface IDevice {
|
||||
|
||||
/**
|
||||
* Returns a {@link SyncService} object to push / pull files to and from the device.
|
||||
* @return <code>null</code> if the SyncService couldn't be created. This can happen if abd
|
||||
* @return <code>null</code> if the SyncService couldn't be created. This can happen if adb
|
||||
* refuse to open the connection because the {@link IDevice} is invalid (or got disconnected).
|
||||
* @throws IOException if the connection with adb failed.
|
||||
*/
|
||||
@@ -211,4 +211,48 @@ public interface IDevice {
|
||||
*/
|
||||
public String getClientName(int pid);
|
||||
|
||||
/**
|
||||
* Installs an Android application on device.
|
||||
* This is a helper method that combines the syncPackageToDevice, installRemotePackage,
|
||||
* and removePackage steps
|
||||
* @param packageFilePath the absolute file system path to file on local host to install
|
||||
* @param reinstall set to <code>true</code> if re-install of app should be performed
|
||||
* @return a {@link String} with an error code, or <code>null</code> if success.
|
||||
* @throws IOException
|
||||
*/
|
||||
public String installPackage(String packageFilePath, boolean reinstall) throws IOException;
|
||||
|
||||
/**
|
||||
* Pushes a file to device
|
||||
* @param localFilePath the absolute path to file on local host
|
||||
* @return {@link String} destination path on device for file
|
||||
* @throws IOException if fatal error occurred when pushing file
|
||||
*/
|
||||
public String syncPackageToDevice(String localFilePath)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Installs the application package that was pushed to a temporary location on the device.
|
||||
* @param remoteFilePath absolute file path to package file on device
|
||||
* @param reinstall set to <code>true</code> if re-install of app should be performed
|
||||
* @throws InstallException if installation failed
|
||||
*/
|
||||
public String installRemotePackage(String remoteFilePath, boolean reinstall)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Remove a file from device
|
||||
* @param remoteFilePath path on device of file to remove
|
||||
* @throws IOException if file removal failed
|
||||
*/
|
||||
public void removeRemotePackage(String remoteFilePath) throws IOException;
|
||||
|
||||
/**
|
||||
* Uninstall an package from the device.
|
||||
* @param packageName the Android application package name to uninstall
|
||||
* @return a {@link String} with an error code, or <code>null</code> if success.
|
||||
* @throws IOException
|
||||
*/
|
||||
public String uninstallPackage(String packageName) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user