Refactor su database

This commit is contained in:
topjohnwu 2017-06-01 00:19:52 +08:00
parent 27879c3f01
commit 9a1dc8ee0e
10 changed files with 228 additions and 209 deletions

View File

@ -6,12 +6,11 @@ import android.content.pm.ApplicationInfo;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.SparseArray;
import android.widget.Toast;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.SafetyNetHelper;
import com.topjohnwu.magisk.utils.Shell;
@ -24,7 +23,6 @@ import java.util.List;
public class MagiskManager extends Application {
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
public static final String MAGISK_HIDE_PATH = "/magisk/.core/magiskhide/";
public static final String TMP_FOLDER_PATH = "/dev/tmp";
public static final String MAGISK_PATH = "/magisk";
public static final String UNINSTALLER = "magisk_uninstaller.sh";
@ -43,7 +41,6 @@ public class MagiskManager extends Application {
public final CallbackEvent<Void> repoLoadDone = new CallbackEvent<>();
public final CallbackEvent<Void> updateCheckDone = new CallbackEvent<>();
public final CallbackEvent<Void> safetyNetDone = new CallbackEvent<>();
public final SparseArray<CallbackEvent<Policy>> uidSuRequest = new SparseArray<>();
// Info
public String magiskVersionString;
@ -80,7 +77,9 @@ public class MagiskManager extends Application {
public int suResponseType;
public int suNotificationType;
// Global resources
public SharedPreferences prefs;
public SuDatabaseHelper suDB;
private static Handler mHandler = new Handler();
@ -88,6 +87,7 @@ public class MagiskManager extends Application {
public void onCreate() {
super.onCreate();
prefs = PreferenceManager.getDefaultSharedPreferences(this);
suDB = new SuDatabaseHelper(this);
}
public void toast(String msg, int duration) {

View File

@ -13,7 +13,6 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.SuLogAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import java.util.List;
@ -28,7 +27,7 @@ public class SuLogFragment extends Fragment {
@BindView(R.id.recyclerView) RecyclerView recyclerView;
private Unbinder unbinder;
private SuLogDatabaseHelper dbHelper;
private MagiskManager magiskManager;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@ -48,8 +47,7 @@ public class SuLogFragment extends Fragment {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
unbinder = ButterKnife.bind(this, v);
dbHelper = new SuLogDatabaseHelper(getActivity());
magiskManager = getApplication();
updateList();
@ -57,7 +55,7 @@ public class SuLogFragment extends Fragment {
}
private void updateList() {
List<SuLogEntry> logs = dbHelper.getLogList();
List<SuLogEntry> logs = magiskManager.suDB.getLogList();
if (logs.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
@ -76,7 +74,7 @@ public class SuLogFragment extends Fragment {
updateList();
return true;
case R.id.menu_clear:
dbHelper.clearLogs();
magiskManager.suDB.clearLogs();
updateList();
return true;
default:

View File

@ -11,7 +11,6 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.PolicyAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
import java.util.List;
@ -33,15 +32,15 @@ public class SuperuserFragment extends Fragment {
unbinder = ButterKnife.bind(this, view);
PackageManager pm = getActivity().getPackageManager();
MagiskManager magiskManager = getApplication();
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
List<Policy> policyList = dbHelper.getPolicyList(pm);
List<Policy> policyList = magiskManager.suDB.getPolicyList(pm);
if (policyList.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
recyclerView.setAdapter(new PolicyAdapter(policyList, dbHelper, pm));
recyclerView.setAdapter(new PolicyAdapter(policyList, magiskManager.suDB, pm));
emptyRv.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}

View File

@ -49,7 +49,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Policy policy = policyList.get(position);
try {
holder.setExpanded(expandList.contains(policy));
holder.itemView.setOnClickListener(view -> {
@ -64,7 +64,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
holder.appName.setText(policy.appName);
holder.packageName.setText(policy.packageName);
holder.appIcon.setImageDrawable(pm.getPackageInfo(policy.packageName, 0).applicationInfo.loadIcon(pm));
holder.appIcon.setImageDrawable(policy.info.loadIcon(pm));
holder.masterSwitch.setOnCheckedChangeListener((v, isChecked) -> {
if ((isChecked && policy.policy == Policy.DENY) ||
(!isChecked && policy.policy == Policy.ALLOW)) {
@ -115,12 +115,6 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
// Hide for now
holder.moreInfo.setVisibility(View.GONE);
} catch (PackageManager.NameNotFoundException e) {
policyList.remove(position);
dbHelper.deletePolicy(policy);
onBindViewHolder(holder, position);
}
}
@Override

View File

@ -6,18 +6,30 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import com.topjohnwu.magisk.utils.Utils;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SuDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 1;
private static final String TABLE_NAME = "policies";
private static final int DATABASE_VER = 2;
private static final String POLICY_TABLE = "policies";
private static final String LOG_TABLE = "logs";
private static final String SETTINGS_TABLE = "settings";
private MagiskManager magiskManager;
private PackageManager pm;
public SuDatabaseHelper(Context context) {
super(context, "su.db", null, DATABASE_VER);
magiskManager = Utils.getMagiskManager(context);
pm = context.getPackageManager();
}
@Override
@ -28,29 +40,78 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 0) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
"(uid INT, package_name TEXT, app_name TEXT, policy INT, " +
"until INT, logging INT, notification INT, " +
"PRIMARY KEY(uid))");
createTables(db);
oldVersion = 2;
}
if (oldVersion == 1) {
// We're dropping column app_name, rename and re-construct table
db.execSQL("ALTER TABLE " + POLICY_TABLE + " RENAME TO " + POLICY_TABLE + "_old");
// Create the new tables
createTables(db);
// Migrate old data to new tables
db.execSQL(
"INSERT INTO " + POLICY_TABLE + " SELECT " +
"uid, package_name, policy, until, logging, notification " +
"FROM " + POLICY_TABLE + "_old");
db.execSQL("DROP TABLE " + POLICY_TABLE + "_old");
File oldDB = magiskManager.getDatabasePath("sulog.db");
if (oldDB.exists()) {
migrateLegacyLogList(oldDB, db);
magiskManager.deleteDatabase("sulog.db");
}
++oldVersion;
}
// Currently new database, no upgrading
}
public boolean deletePolicy(Policy policy) {
private void createTables(SQLiteDatabase db) {
// Policies
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + POLICY_TABLE + " " +
"(uid INT, package_name TEXT, policy INT, " +
"until INT, logging INT, notification INT, " +
"PRIMARY KEY(uid))");
// Logs
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + LOG_TABLE + " " +
"(from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
"to_uid INT, action INT, time INT, command TEXT)");
// Settings
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + SETTINGS_TABLE + " " +
"(key TEXT, value INT, PRIMARY KEY(key))");
}
public void deletePolicy(Policy policy) {
deletePolicy(policy.packageName);
}
public void deletePolicy(String pkg) {
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_NAME, "package_name=?", new String[] { policy.packageName });
db.delete(POLICY_TABLE, "package_name=?", new String[] { pkg });
db.close();
}
public void deletePolicy(int uid) {
SQLiteDatabase db = getWritableDatabase();
db.delete(POLICY_TABLE, "uid=?", new String[]{String.valueOf(uid)});
db.close();
return getPolicy(policy.packageName) == null;
}
public Policy getPolicy(int uid) {
Policy policy = null;
SQLiteDatabase db = getReadableDatabase();
try (Cursor c = db.query(TABLE_NAME, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) {
try (Cursor c = db.query(POLICY_TABLE, null, "uid=?", new String[] { String.valueOf(uid) }, null, null, null)) {
if (c.moveToNext()) {
policy = new Policy(c);
policy = new Policy(c, pm);
}
} catch (PackageManager.NameNotFoundException e) {
deletePolicy(uid);
return null;
}
db.close();
return policy;
@ -59,10 +120,13 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
public Policy getPolicy(String pkg) {
Policy policy = null;
SQLiteDatabase db = getReadableDatabase();
try (Cursor c = db.query(TABLE_NAME, null, "package_name=?", new String[] { pkg }, null, null, null)) {
try (Cursor c = db.query(POLICY_TABLE, null, "package_name=?", new String[] { pkg }, null, null, null)) {
if (c.moveToNext()) {
policy = new Policy(c);
policy = new Policy(c, pm);
}
} catch (PackageManager.NameNotFoundException e) {
deletePolicy(pkg);
return null;
}
db.close();
return policy;
@ -70,13 +134,13 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
public void addPolicy(Policy policy) {
SQLiteDatabase db = getWritableDatabase();
db.replace(TABLE_NAME, null, policy.getContentValues());
db.replace(POLICY_TABLE, null, policy.getContentValues());
db.close();
}
public void updatePolicy(Policy policy) {
SQLiteDatabase db = getWritableDatabase();
db.update(TABLE_NAME, policy.getContentValues(), "package_name=?",
db.update(POLICY_TABLE, policy.getContentValues(), "package_name=?",
new String[] { policy.packageName });
db.close();
}
@ -86,15 +150,60 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
SQLiteDatabase db = getWritableDatabase();
Policy policy;
// Clear outdated policies
db.delete(TABLE_NAME, "until > 0 AND until < ?",
db.delete(POLICY_TABLE, "until > 0 AND until < ?",
new String[] { String.valueOf(System.currentTimeMillis()) });
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, "app_name ASC")) {
try (Cursor c = db.query(POLICY_TABLE, null, null, null, null, null, null)) {
while (c.moveToNext()) {
policy = new Policy(c);
policy = new Policy(c, pm);
ret.add(policy);
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
db.close();
Collections.sort(ret);
return ret;
}
private List<SuLogEntry> getLogList(SQLiteDatabase db, String selection) {
List<SuLogEntry> ret = new ArrayList<>();
// Clear outdated logs
db.delete(LOG_TABLE, "time < ?", new String[] { String.valueOf(
System.currentTimeMillis() / 1000 - magiskManager.suLogTimeout * 86400) });
try (Cursor c = db.query(LOG_TABLE, null, selection, null, null, null, "time DESC")) {
while (c.moveToNext()) {
ret.add(new SuLogEntry(c));
}
}
db.close();
return ret;
}
private void migrateLegacyLogList(File oldDB, SQLiteDatabase newDB) {
SQLiteDatabase db = SQLiteDatabase.openDatabase(oldDB.getPath(), null, SQLiteDatabase.OPEN_READWRITE);
List<SuLogEntry> logs = getLogList(db, null);
for (SuLogEntry log : logs) {
newDB.insert(LOG_TABLE, null, log.getContentValues());
}
}
public List<SuLogEntry> getLogList() {
return getLogList(null);
}
public List<SuLogEntry> getLogList(String selection) {
return getLogList(getWritableDatabase(), selection);
}
public void addLog(SuLogEntry log) {
SQLiteDatabase db = getWritableDatabase();
db.insert(LOG_TABLE, null, log.getContentValues());
db.close();
}
public void clearLogs() {
SQLiteDatabase db = getWritableDatabase();
db.delete(LOG_TABLE, null, null);
db.close();
}
}

View File

@ -1,76 +0,0 @@
package com.topjohnwu.magisk.database;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import java.util.ArrayList;
import java.util.List;
public class SuLogDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VER = 1;
private static final String TABLE_NAME = "logs";
private MagiskManager magiskManager;
public SuLogDatabaseHelper(Context context) {
super(context, "sulog.db", null, DATABASE_VER);
magiskManager = (MagiskManager) context.getApplicationContext();
}
@Override
public void onCreate(SQLiteDatabase db) {
onUpgrade(db, 0, DATABASE_VER);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 0) {
db.execSQL(
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"from_uid INT, package_name TEXT, app_name TEXT, from_pid INT, " +
"to_uid INT, action INT, time INT, command TEXT)");
}
// Currently new database, no upgrading
}
public void addLog(SuLogEntry log) {
SQLiteDatabase db = getWritableDatabase();
db.insert(TABLE_NAME, null, log.getContentValues());
db.close();
}
public void clearLogs() {
SQLiteDatabase db = getWritableDatabase();
db.delete(TABLE_NAME, null, null);
db.close();
}
public List<SuLogEntry> getLogList() {
return getLogList(null);
}
public List<SuLogEntry> getLogList(int uid) {
return getLogList("uid=" + uid);
}
public List<SuLogEntry> getLogList(String selection) {
List<SuLogEntry> ret = new ArrayList<>();
SQLiteDatabase db = getWritableDatabase();
// Clear outdated logs
db.delete(TABLE_NAME, "time < ?", new String[] { String.valueOf(
System.currentTimeMillis() / 1000 - magiskManager.suLogTimeout * 86400) });
try (Cursor c = db.query(TABLE_NAME, null, selection, null, null, null, "time DESC")) {
while (c.moveToNext()) {
ret.add(new SuLogEntry(c));
}
}
db.close();
return ret;
}
}

View File

@ -5,21 +5,18 @@ import android.content.Context;
import android.content.Intent;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Utils;
public class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
SuDatabaseHelper suDB = new SuDatabaseHelper(context);
MagiskManager magiskManager = Utils.getMagiskManager(context);
String pkg = intent.getData().getEncodedSchemeSpecificPart();
Policy policy = suDB.getPolicy(pkg);
Policy policy = magiskManager.suDB.getPolicy(pkg);
if (policy == null)
return;
MagiskManager magiskManager = Utils.getMagiskManager(context);
magiskManager.initSUConfig();
switch (intent.getAction()) {
@ -29,12 +26,12 @@ public class PackageReceiver extends BroadcastReceiver {
if (uid > 0) {
policy.uid = uid % 100000;
}
suDB.updatePolicy(policy);
magiskManager.suDB.updatePolicy(policy);
return;
case Intent.ACTION_PACKAGE_REMOVED:
boolean isUpdate = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (!isUpdate || magiskManager.suReauth) {
suDB.deletePolicy(policy);
magiskManager.suDB.deletePolicy(policy);
}
break;
}

View File

@ -1,12 +1,13 @@
package com.topjohnwu.magisk.superuser;
import android.content.ContentValues;
import android.content.pm.PackageInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.support.annotation.NonNull;
public class Policy {
public class Policy implements Comparable<Policy>{
public static final int INTERACTIVE = 0;
public static final int DENY = 1;
public static final int ALLOW = 2;
@ -15,37 +16,42 @@ public class Policy {
public long until;
public boolean logging = true, notification = true;
public String packageName, appName;
public PackageInfo info;
public ApplicationInfo info;
public Policy(int uid, PackageManager pm) throws PackageManager.NameNotFoundException {
String[] pkgs = pm.getPackagesForUid(uid);
if (pkgs != null && pkgs.length > 0) {
info = pm.getPackageInfo(pkgs[0], 0);
this.uid = uid;
packageName = pkgs[0];
appName = info.applicationInfo.loadLabel(pm).toString();
info = pm.getApplicationInfo(packageName, 0);
appName = info.loadLabel(pm).toString();
} else throw new PackageManager.NameNotFoundException();
}
public Policy(Cursor c) {
public Policy(Cursor c, PackageManager pm) throws PackageManager.NameNotFoundException {
uid = c.getInt(c.getColumnIndex("uid"));
packageName = c.getString(c.getColumnIndex("package_name"));
appName = c.getString(c.getColumnIndex("app_name"));
policy = c.getInt(c.getColumnIndex("policy"));
until = c.getLong(c.getColumnIndex("until"));
logging = c.getInt(c.getColumnIndex("logging")) != 0;
notification = c.getInt(c.getColumnIndex("notification")) != 0;
info = pm.getApplicationInfo(packageName, 0);
appName = info.loadLabel(pm).toString();
}
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("uid", uid);
values.put("package_name", packageName);
values.put("app_name", appName);
values.put("policy", policy);
values.put("until", until);
values.put("logging", logging ? 1 : 0);
values.put("notification", notification ? 1 : 0);
return values;
}
@Override
public int compareTo(@NonNull Policy policy) {
return appName.toLowerCase().compareTo(policy.appName.toLowerCase());
}
}

View File

@ -3,13 +3,12 @@ package com.topjohnwu.magisk.superuser;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Process;
import android.widget.Toast;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
import java.util.Date;
@ -46,12 +45,12 @@ public class SuReceiver extends BroadcastReceiver {
action = intent.getStringExtra("action");
if (action == null) return;
SuDatabaseHelper suDbHelper = new SuDatabaseHelper(context);
policy = suDbHelper.getPolicy(fromUid);
policy = magiskManager.suDB.getPolicy(fromUid);
if (policy == null) {
try {
policy = new Policy(fromUid, context.getPackageManager());
} catch (Throwable throwable) {
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return;
}
}
@ -89,8 +88,7 @@ public class SuReceiver extends BroadcastReceiver {
log.fromPid = pid;
log.command = command;
log.date = new Date();
SuLogDatabaseHelper logDbHelper = new SuLogDatabaseHelper(context);
logDbHelper.addLog(log);
magiskManager.suDB.addLog(log);
}
}
}

View File

@ -21,13 +21,9 @@ import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.utils.CallbackEvent;
import com.topjohnwu.magisk.utils.Logger;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import butterknife.BindView;
import butterknife.ButterKnife;
@ -51,7 +47,6 @@ public class SuRequestActivity extends Activity {
private LocalSocket socket;
private PackageManager pm;
private MagiskManager magiskManager;
private SuDatabaseHelper suDB;
private boolean hasTimeout;
private Policy policy;
@ -64,7 +59,6 @@ public class SuRequestActivity extends Activity {
pm = getPackageManager();
magiskManager = getApplicationContext();
suDB = new SuDatabaseHelper(this);
Intent intent = getIntent();
socketPath = intent.getStringExtra("socket");
@ -109,7 +103,7 @@ public class SuRequestActivity extends Activity {
setContentView(R.layout.activity_request);
ButterKnife.bind(this);
appIcon.setImageDrawable(policy.info.applicationInfo.loadIcon(pm));
appIcon.setImageDrawable(policy.info.loadIcon(pm));
appNameView.setText(policy.appName);
packageNameView.setText(policy.packageName);
@ -180,7 +174,7 @@ public class SuRequestActivity extends Activity {
policy.policy = action;
if (time >= 0) {
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
new SuDatabaseHelper(this).addPolicy(policy);
magiskManager.suDB.addPolicy(policy);
}
handleAction();
}
@ -220,7 +214,7 @@ public class SuRequestActivity extends Activity {
}
int uid = payload.getAsInteger("uid");
policy = suDB.getPolicy(uid);
policy = magiskManager.suDB.getPolicy(uid);
if (policy == null) {
policy = new Policy(uid, pm);
}