Prepare for new database implementation

This commit is contained in:
topjohnwu 2018-10-27 15:08:11 -04:00
parent f17ec9e9d7
commit 2a65c3dc8f
10 changed files with 146 additions and 104 deletions

View File

@ -6,7 +6,7 @@ import android.content.res.Configuration;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
import com.topjohnwu.magisk.database.MagiskDB;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.utils.LocaleManager;
import com.topjohnwu.magisk.utils.RootUtils;
@ -22,7 +22,7 @@ public class MagiskManager extends ContainerApp {
// Global resources
public SharedPreferences prefs;
public MagiskDatabaseHelper mDB;
public MagiskDB mDB;
public RepoDatabaseHelper repoDB;
public MagiskManager() {
@ -38,7 +38,7 @@ public class MagiskManager extends ContainerApp {
Shell.Config.setInitializer(RootUtils.class);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
mDB = MagiskDatabaseHelper.getInstance();
mDB = MagiskDB.getInstance();
String pkg = mDB.getStrings(Const.Key.SU_MANAGER, null);
if (pkg != null && getPackageName().equals(Const.ORIG_PKG_NAME)) {

View File

@ -16,7 +16,7 @@ import com.topjohnwu.magisk.components.CustomAlertDialog;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
import com.topjohnwu.magisk.database.MagiskDB;
import com.topjohnwu.magisk.utils.FingerprintHelper;
import java.util.HashSet;
@ -30,11 +30,11 @@ import butterknife.BindView;
public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder> {
private List<Policy> policyList;
private MagiskDatabaseHelper dbHelper;
private MagiskDB dbHelper;
private PackageManager pm;
private Set<Policy> expandList = new HashSet<>();
public PolicyAdapter(List<Policy> list, MagiskDatabaseHelper db, PackageManager pm) {
public PolicyAdapter(List<Policy> list, MagiskDB db, PackageManager pm) {
policyList = list;
dbHelper = db;
this.pm = pm;

View File

@ -2,6 +2,7 @@ package com.topjohnwu.magisk.adapters;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C extends RecyclerView.ViewHolder>
@ -9,8 +10,9 @@ public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C exte
private static final int SECTION_TYPE = Integer.MIN_VALUE;
@NonNull
@Override
final public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == SECTION_TYPE)
return onCreateSectionViewHolder(parent);
return onCreateItemViewHolder(parent, viewType);
@ -18,7 +20,7 @@ public abstract class SectionedAdapter<S extends RecyclerView.ViewHolder, C exte
@Override
@SuppressWarnings("unchecked")
final public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
PositionInfo info = getPositionInfo(position);
if (info.position == -1)
onBindSectionViewHolder((S) holder, info.section);

View File

@ -1,6 +1,5 @@
package com.topjohnwu.magisk.adapters;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -12,7 +11,7 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.database.MagiskDatabaseHelper;
import com.topjohnwu.magisk.database.MagiskDB;
import java.util.Collections;
import java.util.HashSet;
@ -24,26 +23,25 @@ import butterknife.BindView;
public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, SuLogAdapter.LogViewHolder> {
private List<List<Integer>> logEntryList;
private List<List<SuLogEntry>> logEntries;
private Set<Integer> itemExpanded, sectionExpanded;
private MagiskDatabaseHelper suDB;
private Cursor suLogCursor = null;
private MagiskDB suDB;
public SuLogAdapter(MagiskDatabaseHelper db) {
public SuLogAdapter(MagiskDB db) {
suDB = db;
logEntryList = Collections.emptyList();
logEntries = Collections.emptyList();
sectionExpanded = new HashSet<>();
itemExpanded = new HashSet<>();
}
@Override
public int getSectionCount() {
return logEntryList.size();
return logEntries.size();
}
@Override
public int getItemCount(int section) {
return sectionExpanded.contains(section) ? logEntryList.get(section).size() : 0;
return sectionExpanded.contains(section) ? logEntries.get(section).size() : 0;
}
@Override
@ -60,8 +58,7 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
@Override
public void onBindSectionViewHolder(SectionHolder holder, int section) {
suLogCursor.moveToPosition(logEntryList.get(section).get(0));
SuLogEntry entry = new SuLogEntry(suLogCursor);
SuLogEntry entry = logEntries.get(section).get(0);
holder.arrow.setRotation(sectionExpanded.contains(section) ? 180 : 0);
holder.itemView.setOnClickListener(v -> {
RotateAnimation rotate;
@ -69,11 +66,11 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
holder.arrow.setRotation(0);
rotate = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
sectionExpanded.remove(section);
notifyItemRangeRemoved(getItemPosition(section, 0), logEntryList.get(section).size());
notifyItemRangeRemoved(getItemPosition(section, 0), logEntries.get(section).size());
} else {
rotate = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
sectionExpanded.add(section);
notifyItemRangeInserted(getItemPosition(section, 0), logEntryList.get(section).size());
notifyItemRangeInserted(getItemPosition(section, 0), logEntries.get(section).size());
}
rotate.setDuration(300);
rotate.setFillAfter(true);
@ -84,17 +81,16 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
@Override
public void onBindItemViewHolder(LogViewHolder holder, int section, int position) {
int sqlPosition = logEntryList.get(section).get(position);
suLogCursor.moveToPosition(sqlPosition);
SuLogEntry entry = new SuLogEntry(suLogCursor);
holder.setExpanded(itemExpanded.contains(sqlPosition));
SuLogEntry entry = logEntries.get(section).get(position);
int realIdx = getItemPosition(section, position);
holder.setExpanded(itemExpanded.contains(realIdx));
holder.itemView.setOnClickListener(view -> {
if (holder.isExpanded()) {
holder.collapse();
itemExpanded.remove(sqlPosition);
itemExpanded.remove(realIdx);
} else {
holder.expand();
itemExpanded.add(sqlPosition);
itemExpanded.add(realIdx);
}
});
holder.appName.setText(entry.appName);
@ -106,10 +102,7 @@ public class SuLogAdapter extends SectionedAdapter<SuLogAdapter.SectionHolder, S
}
public void notifyDBChanged() {
if (suLogCursor != null)
suLogCursor.close();
suLogCursor = suDB.getLogCursor();
logEntryList = suDB.getLogStructure();
logEntries = suDB.getLogs();
itemExpanded.clear();
sectionExpanded.clear();
sectionExpanded.add(0);

View File

@ -100,7 +100,6 @@ public class PatchAPK {
repack.delete();
mm.mDB.setStrings(Const.Key.SU_MANAGER, pkg);
mm.mDB.flush();
Data.exportPrefs();
RootUtils.uninstallPkg(Const.ORIG_PKG_NAME);

View File

@ -3,7 +3,6 @@ package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import com.topjohnwu.magisk.utils.Utils;
@ -31,19 +30,19 @@ public class Policy implements Comparable<Policy>{
appName = Utils.getAppLabel(info, pm);
}
public Policy(Cursor c, PackageManager pm) throws PackageManager.NameNotFoundException {
uid = c.getInt(c.getColumnIndex("uid"));
packageName = c.getString(c.getColumnIndex("package_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;
public Policy(ContentValues values, PackageManager pm) throws PackageManager.NameNotFoundException {
uid = values.getAsInteger("uid");
packageName = values.getAsString("package_name");
policy = values.getAsInteger("policy");
until = values.getAsInteger("until");
logging = values.getAsInteger("logging") != 0;
notification = values.getAsInteger("notification") != 0;
info = pm.getApplicationInfo(packageName, 0);
if (info.uid != uid)
throw new PackageManager.NameNotFoundException();
appName = info.loadLabel(pm).toString();
}
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("uid", uid);

View File

@ -1,7 +1,6 @@
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.database.Cursor;
import com.topjohnwu.magisk.utils.LocaleManager;
@ -22,15 +21,15 @@ public class SuLogEntry {
appName = policy.appName;
}
public SuLogEntry(Cursor c) {
fromUid = c.getInt(c.getColumnIndex("from_uid"));
fromPid = c.getInt(c.getColumnIndex("from_pid"));
toUid = c.getInt(c.getColumnIndex("to_uid"));
packageName = c.getString(c.getColumnIndex("package_name"));
appName = c.getString(c.getColumnIndex("app_name"));
command = c.getString(c.getColumnIndex("command"));
action = c.getInt(c.getColumnIndex("action")) != 0;
date = new Date(c.getLong(c.getColumnIndex("time")));
public SuLogEntry(ContentValues values) {
fromUid = values.getAsInteger("from_uid");
packageName = values.getAsString("package_name");
appName = values.getAsString("app_name");
fromPid = values.getAsInteger("from_pid");
command = values.getAsString("command");
toUid = values.getAsInteger("to_uid");
action = values.getAsInteger("action") != 0;
date = new Date(values.getAsLong("time"));
}
public ContentValues getContentValues() {

View File

@ -0,0 +1,60 @@
package com.topjohnwu.magisk.database;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.utils.Utils;
import java.io.File;
import java.util.List;
import androidx.annotation.NonNull;
public abstract class MagiskDB {
public static final int DATABASE_VER = 6;
public static final int OLD_DATABASE_VER = 5;
public static final String POLICY_TABLE = "policies";
public static final String LOG_TABLE = "logs";
public static final String SETTINGS_TABLE = "settings";
public static final String STRINGS_TABLE = "strings";
public static final File LEGACY_MANAGER_DB =
new File(Utils.fmt("/sbin/.core/db-%d/magisk.db", Const.USER_ID));
@NonNull
public static MagiskDB getInstance() {
return MagiskDBLegacy.newInstance();
}
public abstract void clearOutdated();
public void deletePolicy(Policy policy) {
deletePolicy(policy.uid);
}
public abstract void deletePolicy(String pkg);
public abstract void deletePolicy(int uid);
public abstract Policy getPolicy(int uid);
public abstract void addPolicy(Policy policy);
public abstract void updatePolicy(Policy policy);
public abstract List<Policy> getPolicyList();
public abstract List<List<SuLogEntry>> getLogs();
public abstract void addLog(SuLogEntry log);
public abstract void clearLogs();
public abstract void setSettings(String key, int value);
public abstract int getSettings(String key, int defaultValue);
public abstract void setStrings(String key, String value);
public abstract String getStrings(String key, String defaultValue);
}

View File

@ -4,6 +4,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Process;
@ -21,46 +22,29 @@ import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.io.SuFile;
import java.io.File;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import androidx.annotation.NonNull;
public class MagiskDatabaseHelper {
private static final int DATABASE_VER = 6;
private static final int OLD_DATABASE_VER = 5;
private static final String POLICY_TABLE = "policies";
private static final String LOG_TABLE = "logs";
private static final String SETTINGS_TABLE = "settings";
private static final String STRINGS_TABLE = "strings";
private static final File MANAGER_DB =
new File(Utils.fmt("/sbin/.core/db-%d/magisk.db", Const.USER_ID));
public class MagiskDBLegacy extends MagiskDB {
private PackageManager pm;
private SQLiteDatabase db;
@NonNull
public static MagiskDatabaseHelper getInstance() {
static MagiskDBLegacy newInstance() {
try {
return new MagiskDatabaseHelper();
return new MagiskDBLegacy();
} catch (Exception e) {
// Let's cleanup everything and try again
Shell.su("db_clean '*'").exec();
return new MagiskDatabaseHelper();
return new MagiskDBLegacy();
}
}
private MagiskDatabaseHelper() {
private MagiskDBLegacy() {
pm = Data.MM().getPackageManager();
init();
}
private void init() {
db = openDatabase();
db.disableWriteAheadLogging();
int version = Data.magiskVersionCode >= Const.MAGISK_VER.DBVER_SIX ? DATABASE_VER : OLD_DATABASE_VER;
@ -79,7 +63,7 @@ public class MagiskDatabaseHelper {
MagiskManager mm = Data.MM();
Context de = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
? mm.createDeviceProtectedStorageContext() : mm;
if (!MANAGER_DB.canWrite()) {
if (!LEGACY_MANAGER_DB.canWrite()) {
if (!Shell.rootAccess() || Data.magiskVersionCode < 0) {
// We don't want the app to crash, create a db and return
return mm.openOrCreateDatabase("su.db", Context.MODE_PRIVATE, null);
@ -102,7 +86,7 @@ public class MagiskDatabaseHelper {
Shell.su("db_setup " + Process.myUid()).exec();
}
// Not using legacy mode, open the mounted global DB
return SQLiteDatabase.openOrCreateDatabase(MANAGER_DB, null);
return SQLiteDatabase.openOrCreateDatabase(LEGACY_MANAGER_DB, null);
}
private void onUpgrade(SQLiteDatabase db, int oldVersion) {
@ -159,27 +143,23 @@ public class MagiskDatabaseHelper {
// 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))");
"(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)");
"(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 flush() {
db.close();
init();
"(key TEXT, value INT, PRIMARY KEY(key))");
}
@Override
public void clearOutdated() {
// Clear outdated policies
db.delete(POLICY_TABLE, Utils.fmt("until > 0 AND until < %d", System.currentTimeMillis() / 1000), null);
@ -187,23 +167,24 @@ public class MagiskDatabaseHelper {
db.delete(LOG_TABLE, Utils.fmt("time < %d", System.currentTimeMillis() - Data.suLogTimeout * 86400000), null);
}
public void deletePolicy(Policy policy) {
deletePolicy(policy.uid);
}
@Override
public void deletePolicy(String pkg) {
db.delete(POLICY_TABLE, "package_name=?", new String[] { pkg });
}
@Override
public void deletePolicy(int uid) {
db.delete(POLICY_TABLE, Utils.fmt("uid=%d", uid), null);
}
@Override
public Policy getPolicy(int uid) {
Policy policy = null;
try (Cursor c = db.query(POLICY_TABLE, null, Utils.fmt("uid=%d", uid), null, null, null, null)) {
if (c.moveToNext()) {
policy = new Policy(c, pm);
ContentValues values = new ContentValues();
DatabaseUtils.cursorRowToContentValues(c, values);
policy = new Policy(values, pm);
}
} catch (PackageManager.NameNotFoundException e) {
deletePolicy(uid);
@ -212,21 +193,26 @@ public class MagiskDatabaseHelper {
return policy;
}
@Override
public void addPolicy(Policy policy) {
db.replace(POLICY_TABLE, null, policy.getContentValues());
}
@Override
public void updatePolicy(Policy policy) {
db.update(POLICY_TABLE, policy.getContentValues(), Utils.fmt("uid=%d", policy.uid), null);
}
public List<Policy> getPolicyList(PackageManager pm) {
@Override
public List<Policy> getPolicyList() {
try (Cursor c = db.query(POLICY_TABLE, null, Utils.fmt("uid/100000=%d", Const.USER_ID),
null, null, null, null)) {
List<Policy> ret = new ArrayList<>(c.getCount());
while (c.moveToNext()) {
try {
Policy policy = new Policy(c, pm);
ContentValues values = new ContentValues();
DatabaseUtils.cursorRowToContentValues(c, values);
Policy policy = new Policy(values, pm);
ret.add(policy);
} catch (PackageManager.NameNotFoundException e) {
// The app no longer exist, remove from DB
@ -238,11 +224,12 @@ public class MagiskDatabaseHelper {
}
}
public List<List<Integer>> getLogStructure() {
try (Cursor c = db.query(LOG_TABLE, new String[] { "time" }, Utils.fmt("from_uid/100000=%d", Const.USER_ID),
@Override
public List<List<SuLogEntry>> getLogs() {
try (Cursor c = db.query(LOG_TABLE, null, Utils.fmt("from_uid/100000=%d", Const.USER_ID),
null, null, null, "time DESC")) {
List<List<Integer>> ret = new ArrayList<>();
List<Integer> list = null;
List<List<SuLogEntry>> ret = new ArrayList<>();
List<SuLogEntry> list = null;
String dateString = null, newString;
while (c.moveToNext()) {
Date date = new Date(c.getLong(c.getColumnIndex("time")));
@ -252,25 +239,25 @@ public class MagiskDatabaseHelper {
list = new ArrayList<>();
ret.add(list);
}
list.add(c.getPosition());
ContentValues values = new ContentValues();
DatabaseUtils.cursorRowToContentValues(c, values);
list.add(new SuLogEntry(values));
}
return ret;
}
}
public Cursor getLogCursor() {
return db.query(LOG_TABLE, null, Utils.fmt("from_uid/100000=%d", Const.USER_ID),
null, null, null, "time DESC");
}
@Override
public void addLog(SuLogEntry log) {
db.insert(LOG_TABLE, null, log.getContentValues());
}
@Override
public void clearLogs() {
db.delete(LOG_TABLE, null, null);
}
@Override
public void setSettings(String key, int value) {
ContentValues data = new ContentValues();
data.put("key", key);
@ -278,6 +265,7 @@ public class MagiskDatabaseHelper {
db.replace(SETTINGS_TABLE, null, data);
}
@Override
public int getSettings(String key, int defaultValue) {
int value = defaultValue;
try (Cursor c = db.query(SETTINGS_TABLE, null, "key=?",new String[] { key }, null, null, null)) {
@ -288,6 +276,7 @@ public class MagiskDatabaseHelper {
return value;
}
@Override
public void setStrings(String key, String value) {
if (value == null) {
db.delete(STRINGS_TABLE, "key=?", new String[] { key });
@ -299,6 +288,7 @@ public class MagiskDatabaseHelper {
}
}
@Override
public String getStrings(String key, String defaultValue) {
String value = defaultValue;
try (Cursor c = db.query(STRINGS_TABLE, null, "key=?",new String[] { key }, null, null, null)) {

View File

@ -48,7 +48,7 @@ public class SuperuserFragment extends BaseFragment {
}
private void displayPolicyList() {
List<Policy> policyList = mm.mDB.getPolicyList(pm);
List<Policy> policyList = mm.mDB.getPolicyList();
if (policyList.size() == 0) {
emptyRv.setVisibility(View.VISIBLE);