2017-01-24 14:19:28 +08:00
|
|
|
package com.topjohnwu.magisk.superuser;
|
|
|
|
|
|
|
|
import android.content.ContentValues;
|
2017-01-25 16:45:55 +08:00
|
|
|
import android.content.DialogInterface;
|
2017-01-24 14:19:28 +08:00
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.pm.PackageInfo;
|
|
|
|
import android.content.pm.PackageManager;
|
|
|
|
import android.net.LocalSocket;
|
|
|
|
import android.net.LocalSocketAddress;
|
|
|
|
import android.os.AsyncTask;
|
|
|
|
import android.os.Bundle;
|
2017-01-25 02:16:36 +08:00
|
|
|
import android.os.CountDownTimer;
|
2017-01-24 14:19:28 +08:00
|
|
|
import android.support.v7.app.AppCompatActivity;
|
2017-01-25 16:45:55 +08:00
|
|
|
import android.view.MotionEvent;
|
|
|
|
import android.view.View;
|
2017-01-24 14:19:28 +08:00
|
|
|
import android.view.Window;
|
2017-01-25 16:45:55 +08:00
|
|
|
import android.widget.AdapterView;
|
2017-01-24 14:19:28 +08:00
|
|
|
import android.widget.ArrayAdapter;
|
|
|
|
import android.widget.Button;
|
|
|
|
import android.widget.ImageView;
|
2017-01-25 02:16:36 +08:00
|
|
|
import android.widget.LinearLayout;
|
2017-01-24 14:19:28 +08:00
|
|
|
import android.widget.Spinner;
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
|
|
|
import com.topjohnwu.magisk.R;
|
|
|
|
|
|
|
|
import java.io.DataInputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
import butterknife.BindView;
|
|
|
|
import butterknife.ButterKnife;
|
|
|
|
|
|
|
|
public class SuRequestActivity extends AppCompatActivity {
|
|
|
|
|
2017-01-25 04:27:05 +08:00
|
|
|
private static final int[] timeoutList = {0, -1, 10, 20, 30, 60};
|
2017-01-24 14:19:28 +08:00
|
|
|
private final static int SU_PROTOCOL_PARAM_MAX = 20;
|
|
|
|
private final static int SU_PROTOCOL_NAME_MAX = 20;
|
|
|
|
private final static int SU_PROTOCOL_VALUE_MAX = 256;
|
|
|
|
|
2017-01-25 02:16:36 +08:00
|
|
|
@BindView(R.id.su_popup) LinearLayout suPopup;
|
2017-01-24 14:19:28 +08:00
|
|
|
@BindView(R.id.timeout) Spinner timeout;
|
|
|
|
@BindView(R.id.app_icon) ImageView appIcon;
|
|
|
|
@BindView(R.id.app_name) TextView appNameView;
|
|
|
|
@BindView(R.id.package_name) TextView packageNameView;
|
|
|
|
@BindView(R.id.grant_btn) Button grant_btn;
|
|
|
|
@BindView(R.id.deny_btn) Button deny_btn;
|
|
|
|
|
|
|
|
private String socketPath;
|
|
|
|
private LocalSocket socket;
|
|
|
|
private PackageManager pm;
|
|
|
|
private PackageInfo info;
|
|
|
|
|
2017-01-25 02:16:36 +08:00
|
|
|
private int uid, countdown = 10;
|
2017-01-24 14:19:28 +08:00
|
|
|
private String appName, packageName;
|
2017-01-25 02:16:36 +08:00
|
|
|
private CountDownTimer timer;
|
2017-01-24 14:19:28 +08:00
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
|
|
|
|
|
|
|
|
pm = getPackageManager();
|
|
|
|
|
|
|
|
Intent intent = getIntent();
|
|
|
|
socketPath = intent.getStringExtra("socket");
|
|
|
|
|
|
|
|
new SocketManager().execute();
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateUI() throws Throwable {
|
|
|
|
setContentView(R.layout.activity_request);
|
|
|
|
ButterKnife.bind(this);
|
|
|
|
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.timeout, android.R.layout.simple_spinner_item);
|
|
|
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
|
|
|
timeout.setAdapter(adapter);
|
|
|
|
appIcon.setImageDrawable(info.applicationInfo.loadIcon(pm));
|
|
|
|
appNameView.setText(appName);
|
|
|
|
packageNameView.setText(packageName);
|
|
|
|
|
2017-01-25 02:16:36 +08:00
|
|
|
timer = new CountDownTimer(countdown * 1000, 1000) {
|
|
|
|
@Override
|
|
|
|
public void onTick(long millisUntilFinished) {
|
|
|
|
deny_btn.setText(getString(R.string.deny, "(" + millisUntilFinished / 1000 + ")"));
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public void onFinish() {
|
|
|
|
deny_btn.setText(getString(R.string.deny, "(0)"));
|
|
|
|
handleAction(false, -1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-01-24 14:19:28 +08:00
|
|
|
grant_btn.setOnClickListener(v -> handleAction(true, timeoutList[timeout.getSelectedItemPosition()]));
|
2017-01-25 01:23:41 +08:00
|
|
|
deny_btn.setOnClickListener(v -> handleAction(false, timeoutList[timeout.getSelectedItemPosition()]));
|
2017-01-25 16:45:55 +08:00
|
|
|
suPopup.setOnClickListener((v) -> {
|
2017-01-25 02:16:36 +08:00
|
|
|
timer.cancel();
|
|
|
|
deny_btn.setText(getString(R.string.deny, ""));
|
|
|
|
});
|
2017-01-25 16:45:55 +08:00
|
|
|
timeout.setOnTouchListener((v, event) -> {
|
|
|
|
timer.cancel();
|
|
|
|
deny_btn.setText(getString(R.string.deny, ""));
|
|
|
|
return false;
|
|
|
|
});
|
2017-01-25 02:16:36 +08:00
|
|
|
|
|
|
|
timer.start();
|
|
|
|
|
2017-01-24 14:19:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void handleAction(boolean action, int timeout) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
socket.getOutputStream().write((action ? "socket:ALLOW" : "socket:DENY").getBytes());
|
|
|
|
} catch (Exception ignored) {}
|
|
|
|
|
|
|
|
if (timeout >= 0) {
|
|
|
|
Policy policy = new Policy();
|
|
|
|
policy.uid = uid;
|
|
|
|
policy.packageName = packageName;
|
|
|
|
policy.appName = appName;
|
2017-01-25 02:16:36 +08:00
|
|
|
policy.until = (timeout == 0) ? 0 : (System.currentTimeMillis() / 1000 + timeout * 60);
|
2017-01-24 14:19:28 +08:00
|
|
|
policy.policy = action ? 2 : 1;
|
|
|
|
policy.logging = true;
|
|
|
|
policy.notification = true;
|
|
|
|
new SuDatabaseHelper(this).addPolicy(policy);
|
|
|
|
}
|
|
|
|
|
|
|
|
finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
private class SocketManager extends AsyncTask<Void, Void, Boolean> {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected Boolean doInBackground(Void... params) {
|
|
|
|
try{
|
|
|
|
socket = new LocalSocket();
|
|
|
|
socket.connect(new LocalSocketAddress(socketPath, LocalSocketAddress.Namespace.FILESYSTEM));
|
|
|
|
|
|
|
|
DataInputStream is = new DataInputStream(socket.getInputStream());
|
|
|
|
|
|
|
|
ContentValues payload = new ContentValues();
|
|
|
|
|
|
|
|
for (int i = 0; i < SU_PROTOCOL_PARAM_MAX; i++) {
|
|
|
|
|
|
|
|
int nameLen = is.readInt();
|
|
|
|
if (nameLen > SU_PROTOCOL_NAME_MAX)
|
|
|
|
throw new IllegalArgumentException("name length too long: " + nameLen);
|
|
|
|
|
|
|
|
byte[] nameBytes = new byte[nameLen];
|
|
|
|
is.readFully(nameBytes);
|
|
|
|
|
|
|
|
String name = new String(nameBytes);
|
|
|
|
|
|
|
|
int dataLen = is.readInt();
|
|
|
|
if (dataLen > SU_PROTOCOL_VALUE_MAX)
|
|
|
|
throw new IllegalArgumentException(name + " data length too long: " + dataLen);
|
|
|
|
|
|
|
|
byte[] dataBytes = new byte[dataLen];
|
|
|
|
is.readFully(dataBytes);
|
|
|
|
|
|
|
|
String data = new String(dataBytes);
|
|
|
|
|
|
|
|
payload.put(name, data);
|
|
|
|
|
|
|
|
if ("eof".equals(name))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uid = payload.getAsInteger("uid");
|
|
|
|
|
|
|
|
}catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onPostExecute(Boolean result) {
|
|
|
|
try {
|
|
|
|
if (!result) throw new Throwable();
|
|
|
|
String[] pkgs = pm.getPackagesForUid(uid);
|
|
|
|
if (pkgs != null && pkgs.length > 0) {
|
|
|
|
info = pm.getPackageInfo(pkgs[0], 0);
|
|
|
|
packageName = pkgs[0];
|
|
|
|
appName = info.applicationInfo.loadLabel(pm).toString();
|
|
|
|
updateUI();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
throw new Throwable();
|
|
|
|
} catch (Throwable e) {
|
|
|
|
handleAction(false, -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|