Я хочу, чтобы мое приложение могло использовать глобальный экземпляр su
. У меня есть код, который делает это, но я уверен, что столкнулся с состоянием гонки.Java runtime.exec пользователь вводит состояние гонки
Я храню некоторые переменные для su
так:
public static List<Object> rootObjects = Collections.synchronizedList(new ArrayList<>());
protected void onCreate(Bundle savedInstanceState) {
...
if(PreferenceManager.getDefaultSharedPreferences(
getApplicationContext()).getBoolean("use_su", false) && rootObjects.isEmpty())
{
try {
Process process = Runtime.getRuntime().exec("su");
rootObjects.add(process);
InputStream inputStream = new DataInputStream(process.getInputStream());
rootObjects.add(inputStream);
OutputStream outputStream = new DataOutputStream(process.getOutputStream());
rootObjects.add(outputStream);
} catch (IOException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
finally {
synchronized (rootObjects) {
rootObjects.notifyAll();
}
}
}
}
и использовать их так:
byte[] getPrivateKeyAsSuperUser() {
byte[] data = null;
DataInputStream inputStream = null;
DataOutputStream outputStream = null;
if(MainActivity.rootObjects.size() != 3)
synchronized (MainActivity.rootObjects)
{
try {
MainActivity.rootObjects.wait();
} catch (InterruptedException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
}
for(Object rootObj : MainActivity.rootObjects)
{
if(rootObj instanceof DataInputStream)
inputStream = (DataInputStream) rootObj;
else if(rootObj instanceof DataOutputStream)
outputStream = (DataOutputStream) rootObj;
}
try {
outputStream.writeBytes(String.format("cat \"%s\"\n", sshPrivateKey.getAbsolutePath()));
outputStream.flush();
data = readStream(inputStream);
} catch (IOException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
return data;
}
private byte[] readStream(InputStream stream) {
byte[] data = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte buff[] = new byte[1024];
int count = 0;
while (stream.available() != 0 && (count = stream.read(buff)) != -1) {
bos.write(buff, 0, count);
}
data = bos.toByteArray();
//System.out.println(new String(data));
} catch (IOException e) {
Log.d(MainActivity.mainActivity.getPackageName(), e.getLocalizedMessage());
}
return data;
}
Но не ждать, как я ожидал, и я сразу же получить Toast
что возвращенный закрытый ключ недействителен с моей проверкой работоспособности (это, вероятно, null).
Код работает, если я даю Process
завершение инициализации, но я хотел бы, чтобы программа сделала это для меня.
Я пробовал некоторые другие методы синхронизации, такие как блокировки, но, по-видимому, как только вы знаете, если объект заблокирован, ваша информация устарела.
Что является лучшим потокобезопасным подходом к вызову getPrivateKeyAsSuperUser()
ожидать, если Process
не инициализирован правильно?
EDIT:
Я хотел бы добавить, что через какой-то отладки, я обнаружил, что я не хочу ждать процесса инициализации (потому что я ДЕЙСТВИТЕЛЬНО это), но, скорее, о том, что shell, порожденный su
, действителен, чтобы принимать дополнительные команды. Я полагаю, что у меня могла бы быть нитьная труба вроде echo DONE
и петля до тех пор, пока я не получу DONE
назад, но похоже, что это потеряло бы мощность процессора. Если бы кто-то мог предоставить некоторые знания по этому предмету, я был бы чрезвычайно благодарен.
Вы абсолютно правы, так что вы заслуживаете голосования. Я должен использовать синглтон.Я делаю это в другом месте в своем приложении, и я не уверен, почему я этого не сделал. Тем не менее, мне все еще нужна помощь, ожидая, когда моя оболочка вернется в 'su', чтобы быть« интерактивной », так сказать (фактический вопрос). У вас есть предложение по этому поводу? – MeetTitan