Skip to content

Commit 343501b

Browse files
committed
Updated RootShell, Fixed some bugs related to re-using commands (disallowed command re-use)
1 parent d708ae1 commit 343501b

4 files changed

Lines changed: 79 additions & 80 deletions

File tree

build.gradle

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ buildscript {
22
repositories {
33
jcenter()
44
}
5+
6+
repositories {
7+
maven { url 'http://repo1.maven.org/maven2' }
8+
}
9+
510
dependencies {
611
classpath 'com.android.tools.build:gradle:1.5.0'
712
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
@@ -12,8 +17,6 @@ repositories {
1217
jcenter()
1318
}
1419

15-
apply from: 'https://gist.githubusercontent.com/larsgrefer/30b36bd74b162631f143/raw/d4155e673d7908193eb65f9bb6640250d7f282d8/git-version.gradle'
16-
1720
apply plugin: 'com.android.library'
1821

1922
android {
@@ -22,7 +25,7 @@ android {
2225

2326
defaultConfig {
2427
minSdkVersion 11
25-
targetSdkVersion 21
28+
targetSdkVersion 23
2629
versionName project.version
2730
}
2831

@@ -34,39 +37,4 @@ android {
3437

3538
dependencies {
3639
testCompile 'junit:junit:4.12'
37-
}
38-
39-
apply plugin: 'com.github.dcendents.android-maven'
40-
41-
android.libraryVariants.all { variant ->
42-
43-
if (variant.name.contains("release")) {
44-
task("sources${variant.name.capitalize()}Jar", type: Jar) {
45-
from variant.javaCompile.source
46-
classifier = 'sources'
47-
}
48-
49-
task("javadoc${variant.name.capitalize()}", type: Javadoc) {
50-
description "Generates Javadoc for $variant.name."
51-
source = variant.javaCompile.source
52-
ext.androidJar = "${android.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
53-
classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar)
54-
options.links("http://docs.oracle.com/javase/7/docs/api/");
55-
options.links("http://developer.android.com/reference/");
56-
options.addStringOption('Xdoclint:none', '-quiet')
57-
failOnError false
58-
}
59-
60-
task("javadoc${variant.name.capitalize()}Jar", type: Jar, dependsOn: "javadoc${variant.name.capitalize()}") {
61-
description "Generates Javadoc Jar for $variant.name."
62-
classifier = 'javadoc'
63-
from tasks.findByPath("javadoc${variant.name.capitalize()}").destinationDir
64-
}
65-
66-
artifacts {
67-
archives tasks.findByPath("javadoc${variant.name.capitalize()}Jar")
68-
archives tasks.findByPath("sources${variant.name.capitalize()}Jar")
69-
}
70-
}
71-
}
72-
40+
}

src/main/java/com/stericson/RootShell/RootShell.java

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class RootShell {
4545

4646
public static boolean debugMode = false;
4747

48-
public static final String version = "RootShell v1.3";
48+
public static final String version = "RootShell v1.4";
4949

5050
/**
5151
* Setting this to false will disable the handler that is used
@@ -141,6 +141,7 @@ public void commandOutput(int id, String line) {
141141
commandWait(RootShell.getShell(false), command);
142142

143143
} catch (Exception e) {
144+
RootShell.log("Exception: " + e);
144145
return false;
145146
}
146147

@@ -152,11 +153,22 @@ public void commandOutput(int id, String line) {
152153

153154
result.clear();
154155

156+
command = new Command(0, false, cmdToExecute + file) {
157+
@Override
158+
public void commandOutput(int id, String line) {
159+
RootShell.log(line);
160+
result.add(line);
161+
162+
super.commandOutput(id, line);
163+
}
164+
};
165+
155166
try {
156167
RootShell.getShell(true).add(command);
157168
commandWait(RootShell.getShell(true), command);
158169

159170
} catch (Exception e) {
171+
RootShell.log("Exception: " + e);
160172
return false;
161173
}
162174

@@ -176,20 +188,22 @@ public void commandOutput(int id, String line) {
176188

177189
/**
178190
* @param binaryName String that represent the binary to find.
191+
* @param singlePath boolean that represents whether to return a single path or multiple.
179192
*
180193
* @return <code>List<String></code> containing the locations the binary was found at.
181194
*/
182-
public static List<String> findBinary(final String binaryName) {
183-
return findBinary(binaryName, null);
195+
public static List<String> findBinary(String binaryName, boolean singlePath) {
196+
return findBinary(binaryName, null, singlePath);
184197
}
185198

186199
/**
187200
* @param binaryName <code>String</code> that represent the binary to find.
188201
* @param searchPaths <code>List<String></code> which contains the paths to search for this binary in.
202+
* @param singlePath boolean that represents whether to return a single path or multiple.
189203
*
190204
* @return <code>List<String></code> containing the locations the binary was found at.
191205
*/
192-
public static List<String> findBinary(final String binaryName, List<String> searchPaths) {
206+
public static List<String> findBinary(final String binaryName, List<String> searchPaths, boolean singlePath) {
193207

194208
final List<String> foundPaths = new ArrayList<String>();
195209

@@ -228,12 +242,16 @@ public void commandOutput(int id, String line) {
228242
}
229243
};
230244

231-
RootShell.getShell(false).add(cc);
245+
cc = RootShell.getShell(false).add(cc);
232246
commandWait(RootShell.getShell(false), cc);
233247

248+
if(foundPaths.size() > 0 && singlePath) {
249+
break;
250+
}
234251
}
235252

236253
found = !foundPaths.isEmpty();
254+
237255
} catch (Exception e) {
238256
RootShell.log(binaryName + " was not found, more information MAY be available with Debugging on.");
239257
}
@@ -251,6 +269,11 @@ public void commandOutput(int id, String line) {
251269
if (RootShell.exists(path + binaryName)) {
252270
RootShell.log(binaryName + " was found here: " + path);
253271
foundPaths.add(path);
272+
273+
if(foundPaths.size() > 0 && singlePath) {
274+
break;
275+
}
276+
254277
} else {
255278
RootShell.log(binaryName + " was NOT found here: " + path);
256279
}
@@ -394,14 +417,14 @@ public void commandOutput(int id, String line) {
394417
*/
395418
public static boolean isBusyboxAvailable()
396419
{
397-
return (findBinary("busybox")).size() > 0;
420+
return (findBinary("busybox", true)).size() > 0;
398421
}
399422

400423
/**
401424
* @return <code>true</code> if su was found.
402425
*/
403426
public static boolean isRootAvailable() {
404-
return (findBinary("su")).size() > 0;
427+
return (findBinary("su", true)).size() > 0;
405428
}
406429

407430
/**

src/main/java/com/stericson/RootShell/execution/Command.java

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public class Command {
4646

4747
Handler mHandler = null;
4848

49+
//Has this command already been used?
50+
protected boolean used = false;
51+
4952
boolean executing = false;
5053

5154
String[] command = {};
@@ -159,8 +162,8 @@ public final void finish()
159162
}
160163

161164
protected final void finishCommand() {
162-
executing = false;
163-
finished = true;
165+
this.executing = false;
166+
this.finished = true;
164167
this.notifyAll();
165168
}
166169

@@ -202,7 +205,8 @@ protected final void setExitCode(int code) {
202205
}
203206

204207
protected final void startExecution() {
205-
executionMonitor = new ExecutionMonitor();
208+
this.used = true;
209+
executionMonitor = new ExecutionMonitor(this);
206210
executionMonitor.setPriority(Thread.MIN_PRIORITY);
207211
executionMonitor.start();
208212
executing = true;
@@ -259,34 +263,28 @@ protected final void output(int id, String line) {
259263
}
260264
}
261265

262-
public final void resetCommand()
263-
{
264-
this.finished = false;
265-
this.totalOutput = 0;
266-
this.totalOutputProcessed = 0;
267-
this.executing = false;
268-
this.terminated = false;
269-
this.exitCode = -1;
270-
}
271-
272266
private class ExecutionMonitor extends Thread {
273267

268+
private final Command command;
269+
270+
public ExecutionMonitor(Command command) {
271+
this.command = command;
272+
}
273+
274274
public void run() {
275275

276-
if(timeout > 0)
276+
if(command.timeout > 0)
277277
{
278-
//We need to kill the command after the given timeout
279-
while (!finished) {
280-
281-
synchronized (Command.this) {
282-
try {
283-
Command.this.wait(timeout);
284-
} catch (InterruptedException e) {
285-
}
278+
synchronized (command) {
279+
try {
280+
RootShell.log("Command " + command.id + " is waiting for: " + command.timeout);
281+
command.wait(command.timeout);
282+
} catch (InterruptedException e) {
283+
RootShell.log("Exception: " + e);
286284
}
287285

288-
if (!finished) {
289-
RootShell.log("Timeout Exception has occurred.");
286+
if (!command.isFinished()) {
287+
RootShell.log("Timeout Exception has occurred for command: " + command.id + ".");
290288
terminate("Timeout Exception");
291289
}
292290
}

src/main/java/com/stericson/RootShell/execution/Shell.java

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -251,13 +251,17 @@ public Command add(Command command) throws IOException {
251251
"Unable to add commands to a closed shell");
252252
}
253253

254+
if(command.used) {
255+
//The command has been used, don't re-use...
256+
throw new IllegalStateException(
257+
"This command has already been executed. (Don't re-use command instances.)");
258+
}
259+
254260
while (this.isCleaning) {
255261
//Don't add commands while cleaning
256262
;
257263
}
258264

259-
command.resetCommand();
260-
261265
this.commands.add(command);
262266

263267
this.notifyThreads();
@@ -594,10 +598,15 @@ public void run() {
594598
cmd.startExecution();
595599
RootShell.log("Executing: " + cmd.getCommand() + " with context: " + shellContext);
596600

601+
//write the command
597602
outputStream.write(cmd.getCommand());
603+
outputStream.flush();
604+
605+
//write the token...
598606
String line = "\necho " + token + " " + totalExecuted + " $?\n";
599607
outputStream.write(line);
600608
outputStream.flush();
609+
601610
write++;
602611
totalExecuted++;
603612
} else if (close) {
@@ -611,11 +620,10 @@ public void run() {
611620
return;
612621
}
613622
}
614-
} catch (IOException e) {
615-
RootShell.log(e.getMessage(), RootShell.LogLevel.ERROR, e);
616-
} catch (InterruptedException e) {
623+
} catch (IOException | InterruptedException e) {
617624
RootShell.log(e.getMessage(), RootShell.LogLevel.ERROR, e);
618-
} finally {
625+
}
626+
finally {
619627
write = 0;
620628
closeQuietly(outputStream);
621629
}
@@ -687,6 +695,7 @@ public void run() {
687695
/**
688696
* token is suffix of output, send output part to implementer
689697
*/
698+
RootShell.log("Found token, line: " + outputLine);
690699
command.output(command.id, outputLine.substring(0, pos));
691700
}
692701

@@ -741,6 +750,7 @@ public void run() {
741750

742751
command.setExitCode(exitCode);
743752
command.commandFinished();
753+
744754
command = null;
745755

746756
read++;
@@ -814,12 +824,12 @@ public void processErrors(Command command) {
814824
}
815825
}
816826

817-
public static void runRootCommand(Command command) throws IOException, TimeoutException, RootDeniedException {
818-
Shell.startRootShell().add(command);
827+
public static Command runRootCommand(Command command) throws IOException, TimeoutException, RootDeniedException {
828+
return Shell.startRootShell().add(command);
819829
}
820830

821-
public static void runCommand(Command command) throws IOException, TimeoutException {
822-
Shell.startShell().add(command);
831+
public static Command runCommand(Command command) throws IOException, TimeoutException {
832+
return Shell.startShell().add(command);
823833
}
824834

825835
public static Shell startRootShell() throws IOException, TimeoutException, RootDeniedException {

0 commit comments

Comments
 (0)