From b3ca9154594a628393cf3587e9874d63d913a3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 27 Apr 2014 21:40:22 +0200 Subject: [PATCH] RootInstaller: multiple apks --- .../fdroid/fdroid/installer/Installer.java | 16 ++- .../fdroid/installer/RootInstaller.java | 105 ++++++++++++++---- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/org/fdroid/fdroid/installer/Installer.java b/src/org/fdroid/fdroid/installer/Installer.java index ec3a97e33..bc0cc549c 100644 --- a/src/org/fdroid/fdroid/installer/Installer.java +++ b/src/org/fdroid/fdroid/installer/Installer.java @@ -20,6 +20,7 @@ package org.fdroid.fdroid.installer; import java.io.File; +import java.util.List; import org.fdroid.fdroid.Preferences; @@ -74,12 +75,11 @@ abstract public class Installer { */ public interface InstallerCallback { - public static final int OPERATION_GENERIC_ERROR = 0; public static final int OPERATION_INSTALL = 1; public static final int OPERATION_DELETE = 2; public void onSuccess(int operation, boolean unattended); - + public void onError(int operation, boolean unattended, String reason); } @@ -186,6 +186,18 @@ abstract public class Installer { // extended class now actually installs the package } + public void installPackage(List apkFiles) throws AndroidNotCompatibleException { + // check if files exist... + for (File apkFile : apkFiles) { + if (!apkFile.exists()) { + Log.d(TAG, "Couldn't find file " + apkFile + " to install."); + return; + } + } + + // extended class now actually installs the package + } + public void deletePackage(String packageName) throws AndroidNotCompatibleException { // check if package exists before proceeding... try { diff --git a/src/org/fdroid/fdroid/installer/RootInstaller.java b/src/org/fdroid/fdroid/installer/RootInstaller.java index 2d66a3335..14697d76d 100644 --- a/src/org/fdroid/fdroid/installer/RootInstaller.java +++ b/src/org/fdroid/fdroid/installer/RootInstaller.java @@ -20,6 +20,7 @@ package org.fdroid.fdroid.installer; import java.io.File; +import java.util.ArrayList; import java.util.List; import eu.chainfire.libsuperuser.Shell; @@ -39,17 +40,21 @@ public class RootInstaller extends Installer { super(context, pm, callback); } - @Override - public void installPackage(final File apkFile) throws AndroidNotCompatibleException { - super.installPackage(apkFile); - + private Shell.Builder createShellBuilder() { Shell.Builder shellBuilder = new Shell.Builder() .useSU() .setWantSTDERR(true) .setWatchdogTimeout(5) .setMinimalLogging(true); - rootSession = shellBuilder.open(new Shell.OnCommandResultListener() { + return shellBuilder; + } + + @Override + public void installPackage(final File apkFile) throws AndroidNotCompatibleException { + super.installPackage(apkFile); + + rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() { // Callback to report whether the shell was successfully // started up @@ -63,11 +68,37 @@ public class RootInstaller extends Installer { // Shell.OnCommandResultListener.SHELL_EXEC_FAILED // TODO - mCallback.onError(InstallerCallback.OPERATION_GENERIC_ERROR, true, + mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, "Error opening root shell with exitCode " + exitCode); } else { - // Shell is up: send our first request - sendInstallCommand(apkFile); + addInstallCommand(apkFile); + } + } + }); + } + + @Override + public void installPackage(final List apkFiles) throws AndroidNotCompatibleException { + super.installPackage(apkFiles); + + rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() { + + // Callback to report whether the shell was successfully + // started up + @Override + public void onCommandResult(int commandCode, int exitCode, List output) { + if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) { + // TODO + // wrong uid + // Shell.OnCommandResultListener.SHELL_WRONG_UID + // exec failed + // Shell.OnCommandResultListener.SHELL_EXEC_FAILED + + // TODO + mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, + "Error opening root shell with exitCode " + exitCode); + } else { + addInstallCommand(apkFiles); } } }); @@ -77,13 +108,7 @@ public class RootInstaller extends Installer { public void deletePackage(final String packageName) throws AndroidNotCompatibleException { super.deletePackage(packageName); - Shell.Builder shellBuilder = new Shell.Builder() - .useSU() - .setWantSTDERR(true) - .setWatchdogTimeout(5) - .setMinimalLogging(true); - - rootSession = shellBuilder.open(new Shell.OnCommandResultListener() { + rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() { // Callback to report whether the shell was successfully // started up @@ -97,11 +122,10 @@ public class RootInstaller extends Installer { // Shell.OnCommandResultListener.SHELL_EXEC_FAILED // TODO - mCallback.onError(InstallerCallback.OPERATION_GENERIC_ERROR, true, + mCallback.onError(InstallerCallback.OPERATION_DELETE, true, "Error opening root shell with exitCode " + exitCode); } else { - // Shell is up: send our first request - sendDeleteCommand(packageName); + addDeleteCommand(packageName); } } }); @@ -114,7 +138,48 @@ public class RootInstaller extends Installer { return false; } - private void sendInstallCommand(File apkFile) { + private void addInstallCommand(List apkFiles) { + ArrayList commands = new ArrayList(); + String pm = "pm install -r "; + for (File apkFile : apkFiles) { + commands.add(pm + apkFile.getAbsolutePath()); + } + + rootSession.addCommand(commands, 0, + new Shell.OnCommandResultListener() { + public void onCommandResult(int commandCode, int exitCode, + List output) { + // close su shell + rootSession.close(); + + if (exitCode < 0) { + // TODO + mCallback.onError(InstallerCallback.OPERATION_INSTALL, true, + "Install failed with exit code " + exitCode); + } else { + // wait until Android's internal PackageManger + // has received the new package state + Thread wait = new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + } + + mCallback.onSuccess( + InstallerCallback.OPERATION_INSTALL, + true); + } + }); + wait.start(); + } + } + }); + + } + + private void addInstallCommand(File apkFile) { rootSession.addCommand("pm install -r " + apkFile.getAbsolutePath(), 0, new Shell.OnCommandResultListener() { public void onCommandResult(int commandCode, int exitCode, List output) { @@ -145,7 +210,7 @@ public class RootInstaller extends Installer { }); } - private void sendDeleteCommand(String packageName) { + private void addDeleteCommand(String packageName) { rootSession.addCommand("pm uninstall " + packageName, 0, new Shell.OnCommandResultListener() { public void onCommandResult(int commandCode, int exitCode, List output) {