一、请求
1、在控制台切换用户 如“su”或应用程序请求获取时都会在SuReceiver中收到信息,并将数据保存到数据库
其中SuDatabaseHelper操作的uid_policy是保存root授权“允许”或“拒绝”的数据库
SuperUserDatabaseHelper操作的log数据库是记录log日志的数库
public void onReceive(final Context context, Intent intent) {
if (intent == null)
return;
String command = intent.getStringExtra("command");
if (command == null)
return;
int uid = intent.getIntExtra("uid", -1);
if (uid == -1)
return;
int desiredUid = intent.getIntExtra("desired_uid", -1);
if (desiredUid == -1)
return;
String action = intent.getStringExtra("action");
if (action == null)
return;
String fromName = intent.getStringExtra("from_name");
String desiredName = intent.getStringExtra("desired_name");
final LogEntry le = new LogEntry();
le.uid = uid;
le.command = command;
le.action = action;
le.desiredUid = desiredUid;
le.desiredName = desiredName;
le.username = fromName;
le.date = (int)(System.currentTimeMillis() / 1000);
le.getPackageInfo(context);
UidPolicy u = SuperuserDatabaseHelper.addLog(context, le);//将日志信息保存到数据库
String toast;
//弹出授权或者拒绝的土司
if (UidPolicy.ALLOW.equals(action)) {
toast = context.getString(R.string.superuser_granted, le.getName());
}
else {
toast = context.getString(R.string.superuser_denied, le.getName());
}
............
}
二、授权
1、在控制台输入su获取权root限或者是应用程序请求root权限时,会启动com.koushikdutta.superuser.MultitaskSuRequestActivity这个类,并传入一个带有通信地址的intent,通过该intent可以获取到与su交互的socket的路径
Intent intent = getIntent();
if (intent == null) {
finish();
return;
}
mSocketPath = intent.getStringExtra("socket");
if (mSocketPath == null) {
finish();
return;
}
2、在manageSocket() 方法中,通过intent中获取到的路径,创建socket与su交互
mSocket = new LocalSocket();
mSocket.connect(new LocalSocketAddress(mSocketPath, Namespace.FILESYSTEM));
3、在弹出的界面中点击“允许”会执行下面的方法
mAllow.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (!Settings.isPinProtected(MultitaskSuRequestActivity.this)) {
approve();
return;
}
.......
});
在approve()方法中
void approve() {
mAllow.setEnabled(false);//设置“允许”键不可用
mDeny.setEnabled(false);//设置“拒绝”键不可用
handleAction(true, null);//真正处理逻辑的方法
}
4、在弹出的界面中点击“拒绝”会执行下面的方法
mDeny.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
deny();
}
});
void deny() {
mAllow.setEnabled(false);
mDeny.setEnabled(false);
handleAction(false, null);//第一个参数是false
}
5、如果不处理,会通过下面的方法过一段时间后关闭该activity
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (isFinishing())
return;
if (!mHandled)
handleAction(false, -1);//第二个参数为-1
}
}, Settings.getRequestTimeout(this) * 1000);
6、当按“返回键”或其它情况执行onDestroy()方法时,
@Override
protected void onDestroy() {
super.onDestroy();
if (!mHandled)
handleAction(false, -1);//与延迟关闭时执行相同的方法,第二个参数为-1
try {
if (mSocket != null)//关闭此次socket连接
mSocket.close();
}
catch (Exception ex) {
}
new File(mSocketPath).delete();
}
7、 void handleAction(boolean action, Integer until) {
System.out.println("mSocket传入的mHandled:"+mHandled);
Assert.assertTrue(!mHandled);
System.out.println("mSocket断定以后mHandled:"+mHandled);
mHandled = true;
try {
mSocket.getOutputStream().write((action ? "socket:ALLOW" : "socket:DENY").getBytes());
System.out.println("mSocket写了action:"+action);
}
catch (Exception ex) {
ex.printStackTrace();
}
try {
if (until == null) {
until = getUntil();
}
// got a policy? let's set it.
//延迟关闭即第5步骤的方法或onDestory()中的方法,第二个参数为-1,不会执行下面的方法,不会保存到数据库,即不会记录此次“同意”或“拒绝”的条目,在
//首界面的同意或拒绝条目中不会看到该应用的数据
if (until != -1) {
UidPolicy policy = new UidPolicy();
policy.policy = action ? UidPolicy.ALLOW : UidPolicy.DENY;
policy.uid = mCallerUid;
// for now just approve all commands, since per command approval is stupid
policy.command = null;
policy.until = until;
policy.desiredUid = mDesiredUid;
SuDatabaseHelper.setPolicy(this, policy);//将数据保存到数据库中
}
// TODO: logging? or should su binary handle that via broadcast?
// Probably the latter, so it is consolidated and from the system of record.
}
catch (Exception ex) {
}
finish();
}