Repository navigation
Expand file tree
/
Copy pathRoot.java
More file actions
144 lines (132 loc) · 5.02 KB
/
Copy pathRoot.java
File metadata and controls
144 lines (132 loc) · 5.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package app.tilescreen;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.OutputStream;
/**
* Root, where the tablet has it (Magisk): one shell kept open, used to drive the backlight directly so a level of 0
* really turns it off. Everything still works without it.
*/
final class Root {
private static Process shell;
private static OutputStream in;
private static Boolean available;
private static String backlight;
private static int max = 255;
private Root() {}
/** Asks for root once (Magisk shows its prompt the first time); true when granted. */
static synchronized boolean available() {
if (available != null) return available;
try {
shell = Runtime.getRuntime().exec("su");
in = shell.getOutputStream();
in.write("id\n".getBytes("UTF-8"));
in.flush();
Thread.sleep(300);
available = isAlive(shell);
} catch (Exception e) {
available = false;
}
App.get().log(available ? "root: granted" : "root: not available (fine; the backlight can't go fully off)");
return available;
}
private static boolean isAlive(Process p) {
try {
p.exitValue();
return false;
} catch (IllegalThreadStateException running) {
return true;
}
}
/** The backlight's sysfs file, or null. */
static synchronized String backlight() {
if (backlight != null) return backlight;
String[] candidates = {"/sys/class/leds/lcd-backlight/brightness"};
for (String c : candidates) {
if (new File(c).exists()) backlight = c;
}
if (backlight == null) {
File[] dirs = new File("/sys/class/backlight").listFiles();
if (dirs != null && dirs.length > 0) backlight = dirs[0].getPath() + "/brightness";
}
if (backlight != null) {
String m = read(backlight.replace("/brightness", "/max_brightness"));
try {
if (m != null) max = Integer.parseInt(m.trim());
} catch (NumberFormatException ignored) {
}
}
return backlight;
}
static synchronized int max() {
backlight();
return max;
}
/** Writes the backlight's raw level through root; false without root. */
static synchronized boolean writeBacklight(int raw) {
String path = backlight();
if (path == null || !available() || !isAlive(shell)) return false;
try {
in.write(("echo " + Math.max(0, Math.min(max, raw)) + " > " + path + "\n").getBytes("UTF-8"));
in.flush();
return true;
} catch (Exception e) {
App.get().log("root: writing the backlight failed: " + e);
return false;
}
}
/** Runs a command in the root shell without waiting for it; false without root. */
static synchronized boolean run(String command) {
if (!available() || !isAlive(shell)) return false;
try {
in.write((command + "\n").getBytes("UTF-8"));
in.flush();
App.get().log("root: " + command);
return true;
} catch (Exception e) {
App.get().log("root: " + command + " failed: " + e);
return false;
}
}
/** Runs a command as root in a shell of its own and waits for it (at most 10 s); true when it succeeded. */
static boolean exec(String command) {
if (!available()) return false;
try {
Process p = Runtime.getRuntime().exec(new String[]{"su", "-c", command});
p.getOutputStream().close();
java.io.InputStream err = p.getErrorStream();
long until = System.currentTimeMillis() + 10000;
while (System.currentTimeMillis() < until) {
try {
int code = p.exitValue();
byte[] b = new byte[512];
int n = err.available() > 0 ? err.read(b) : 0;
App.get().log("root: " + command + " -> " + code + (n > 0 ? " " + new String(b, 0, n, "UTF-8").trim() : ""));
return code == 0;
} catch (IllegalThreadStateException running) {
Thread.sleep(100);
}
}
p.destroy();
App.get().log("root: " + command + " timed out");
} catch (Exception e) {
App.get().log("root: " + command + " failed: " + e);
}
return false;
}
/** The backlight's raw level now, if the file can be read. */
static String readBacklight() {
String path = backlight();
return path == null ? null : read(path);
}
private static String read(String path) {
try {
BufferedReader r = new BufferedReader(new FileReader(path));
String s = r.readLine();
r.close();
return s == null ? null : s.trim();
} catch (Exception e) {
return null;
}
}
}