mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 23:47:39 +00:00
Refactor su database
This commit is contained in:
parent
27879c3f01
commit
9a1dc8ee0e
@ -6,12 +6,11 @@ import android.content.pm.ApplicationInfo;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.SparseArray;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.module.Module;
|
import com.topjohnwu.magisk.module.Module;
|
||||||
import com.topjohnwu.magisk.module.Repo;
|
import com.topjohnwu.magisk.module.Repo;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
|
||||||
import com.topjohnwu.magisk.utils.CallbackEvent;
|
import com.topjohnwu.magisk.utils.CallbackEvent;
|
||||||
import com.topjohnwu.magisk.utils.SafetyNetHelper;
|
import com.topjohnwu.magisk.utils.SafetyNetHelper;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
@ -24,7 +23,6 @@ import java.util.List;
|
|||||||
public class MagiskManager extends Application {
|
public class MagiskManager extends Application {
|
||||||
|
|
||||||
public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk";
|
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 TMP_FOLDER_PATH = "/dev/tmp";
|
||||||
public static final String MAGISK_PATH = "/magisk";
|
public static final String MAGISK_PATH = "/magisk";
|
||||||
public static final String UNINSTALLER = "magisk_uninstaller.sh";
|
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> repoLoadDone = new CallbackEvent<>();
|
||||||
public final CallbackEvent<Void> updateCheckDone = new CallbackEvent<>();
|
public final CallbackEvent<Void> updateCheckDone = new CallbackEvent<>();
|
||||||
public final CallbackEvent<Void> safetyNetDone = new CallbackEvent<>();
|
public final CallbackEvent<Void> safetyNetDone = new CallbackEvent<>();
|
||||||
public final SparseArray<CallbackEvent<Policy>> uidSuRequest = new SparseArray<>();
|
|
||||||
|
|
||||||
// Info
|
// Info
|
||||||
public String magiskVersionString;
|
public String magiskVersionString;
|
||||||
@ -80,7 +77,9 @@ public class MagiskManager extends Application {
|
|||||||
public int suResponseType;
|
public int suResponseType;
|
||||||
public int suNotificationType;
|
public int suNotificationType;
|
||||||
|
|
||||||
|
// Global resources
|
||||||
public SharedPreferences prefs;
|
public SharedPreferences prefs;
|
||||||
|
public SuDatabaseHelper suDB;
|
||||||
|
|
||||||
private static Handler mHandler = new Handler();
|
private static Handler mHandler = new Handler();
|
||||||
|
|
||||||
@ -88,6 +87,7 @@ public class MagiskManager extends Application {
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
suDB = new SuDatabaseHelper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toast(String msg, int duration) {
|
public void toast(String msg, int duration) {
|
||||||
|
@ -13,7 +13,6 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
import com.topjohnwu.magisk.adapters.SuLogAdapter;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
import com.topjohnwu.magisk.superuser.SuLogEntry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -28,7 +27,7 @@ public class SuLogFragment extends Fragment {
|
|||||||
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
@BindView(R.id.recyclerView) RecyclerView recyclerView;
|
||||||
|
|
||||||
private Unbinder unbinder;
|
private Unbinder unbinder;
|
||||||
private SuLogDatabaseHelper dbHelper;
|
private MagiskManager magiskManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
@ -48,8 +47,7 @@ public class SuLogFragment extends Fragment {
|
|||||||
// Inflate the layout for this fragment
|
// Inflate the layout for this fragment
|
||||||
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
View v = inflater.inflate(R.layout.fragment_su_log, container, false);
|
||||||
unbinder = ButterKnife.bind(this, v);
|
unbinder = ButterKnife.bind(this, v);
|
||||||
|
magiskManager = getApplication();
|
||||||
dbHelper = new SuLogDatabaseHelper(getActivity());
|
|
||||||
|
|
||||||
updateList();
|
updateList();
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ public class SuLogFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateList() {
|
private void updateList() {
|
||||||
List<SuLogEntry> logs = dbHelper.getLogList();
|
List<SuLogEntry> logs = magiskManager.suDB.getLogList();
|
||||||
|
|
||||||
if (logs.size() == 0) {
|
if (logs.size() == 0) {
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
@ -76,7 +74,7 @@ public class SuLogFragment extends Fragment {
|
|||||||
updateList();
|
updateList();
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_clear:
|
case R.id.menu_clear:
|
||||||
dbHelper.clearLogs();
|
magiskManager.suDB.clearLogs();
|
||||||
updateList();
|
updateList();
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -11,7 +11,6 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
import com.topjohnwu.magisk.adapters.PolicyAdapter;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -33,15 +32,15 @@ public class SuperuserFragment extends Fragment {
|
|||||||
unbinder = ButterKnife.bind(this, view);
|
unbinder = ButterKnife.bind(this, view);
|
||||||
|
|
||||||
PackageManager pm = getActivity().getPackageManager();
|
PackageManager pm = getActivity().getPackageManager();
|
||||||
|
MagiskManager magiskManager = getApplication();
|
||||||
|
|
||||||
SuDatabaseHelper dbHelper = new SuDatabaseHelper(getActivity());
|
List<Policy> policyList = magiskManager.suDB.getPolicyList(pm);
|
||||||
List<Policy> policyList = dbHelper.getPolicyList(pm);
|
|
||||||
|
|
||||||
if (policyList.size() == 0) {
|
if (policyList.size() == 0) {
|
||||||
emptyRv.setVisibility(View.VISIBLE);
|
emptyRv.setVisibility(View.VISIBLE);
|
||||||
recyclerView.setVisibility(View.GONE);
|
recyclerView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
recyclerView.setAdapter(new PolicyAdapter(policyList, dbHelper, pm));
|
recyclerView.setAdapter(new PolicyAdapter(policyList, magiskManager.suDB, pm));
|
||||||
emptyRv.setVisibility(View.GONE);
|
emptyRv.setVisibility(View.GONE);
|
||||||
recyclerView.setVisibility(View.VISIBLE);
|
recyclerView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
@ -49,78 +49,72 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||||
Policy policy = policyList.get(position);
|
Policy policy = policyList.get(position);
|
||||||
try {
|
|
||||||
holder.setExpanded(expandList.contains(policy));
|
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(view -> {
|
holder.setExpanded(expandList.contains(policy));
|
||||||
if (holder.mExpanded) {
|
|
||||||
holder.collapse();
|
|
||||||
expandList.remove(policy);
|
|
||||||
} else {
|
|
||||||
holder.expand();
|
|
||||||
expandList.add(policy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
holder.appName.setText(policy.appName);
|
holder.itemView.setOnClickListener(view -> {
|
||||||
holder.packageName.setText(policy.packageName);
|
if (holder.mExpanded) {
|
||||||
holder.appIcon.setImageDrawable(pm.getPackageInfo(policy.packageName, 0).applicationInfo.loadIcon(pm));
|
holder.collapse();
|
||||||
holder.masterSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
expandList.remove(policy);
|
||||||
if ((isChecked && policy.policy == Policy.DENY) ||
|
} else {
|
||||||
(!isChecked && policy.policy == Policy.ALLOW)) {
|
holder.expand();
|
||||||
policy.policy = isChecked ? Policy.ALLOW : Policy.DENY;
|
expandList.add(policy);
|
||||||
String message = v.getContext().getString(
|
}
|
||||||
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
});
|
||||||
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
|
||||||
dbHelper.updatePolicy(policy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
|
||||||
if ((isChecked && !policy.notification) ||
|
|
||||||
(!isChecked && policy.notification)) {
|
|
||||||
policy.notification = isChecked;
|
|
||||||
String message = v.getContext().getString(
|
|
||||||
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
|
||||||
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
|
||||||
dbHelper.updatePolicy(policy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
|
||||||
if ((isChecked && !policy.logging) ||
|
|
||||||
(!isChecked && policy.logging)) {
|
|
||||||
policy.logging = isChecked;
|
|
||||||
String message = v.getContext().getString(
|
|
||||||
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
|
||||||
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
|
||||||
dbHelper.updatePolicy(policy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
|
|
||||||
.setTitle(R.string.su_revoke_title)
|
|
||||||
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
|
|
||||||
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
|
||||||
policyList.remove(position);
|
|
||||||
notifyItemRemoved(position);
|
|
||||||
notifyItemRangeChanged(position, policyList.size());
|
|
||||||
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
|
||||||
Snackbar.LENGTH_SHORT).show();
|
|
||||||
dbHelper.deletePolicy(policy);
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
|
||||||
.setCancelable(true)
|
|
||||||
.show());
|
|
||||||
holder.masterSwitch.setChecked(policy.policy == Policy.ALLOW);
|
|
||||||
holder.notificationSwitch.setChecked(policy.notification);
|
|
||||||
holder.loggingSwitch.setChecked(policy.logging);
|
|
||||||
|
|
||||||
// Hide for now
|
holder.appName.setText(policy.appName);
|
||||||
holder.moreInfo.setVisibility(View.GONE);
|
holder.packageName.setText(policy.packageName);
|
||||||
|
holder.appIcon.setImageDrawable(policy.info.loadIcon(pm));
|
||||||
|
holder.masterSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
|
if ((isChecked && policy.policy == Policy.DENY) ||
|
||||||
|
(!isChecked && policy.policy == Policy.ALLOW)) {
|
||||||
|
policy.policy = isChecked ? Policy.ALLOW : Policy.DENY;
|
||||||
|
String message = v.getContext().getString(
|
||||||
|
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
||||||
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
|
dbHelper.updatePolicy(policy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
|
if ((isChecked && !policy.notification) ||
|
||||||
|
(!isChecked && policy.notification)) {
|
||||||
|
policy.notification = isChecked;
|
||||||
|
String message = v.getContext().getString(
|
||||||
|
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
||||||
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
|
dbHelper.updatePolicy(policy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
|
if ((isChecked && !policy.logging) ||
|
||||||
|
(!isChecked && policy.logging)) {
|
||||||
|
policy.logging = isChecked;
|
||||||
|
String message = v.getContext().getString(
|
||||||
|
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
||||||
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
|
dbHelper.updatePolicy(policy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
|
||||||
|
.setTitle(R.string.su_revoke_title)
|
||||||
|
.setMessage(v.getContext().getString(R.string.su_revoke_msg, policy.appName))
|
||||||
|
.setPositiveButton(R.string.yes, (dialog, which) -> {
|
||||||
|
policyList.remove(position);
|
||||||
|
notifyItemRemoved(position);
|
||||||
|
notifyItemRangeChanged(position, policyList.size());
|
||||||
|
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
||||||
|
Snackbar.LENGTH_SHORT).show();
|
||||||
|
dbHelper.deletePolicy(policy);
|
||||||
|
})
|
||||||
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
|
.setCancelable(true)
|
||||||
|
.show());
|
||||||
|
holder.masterSwitch.setChecked(policy.policy == Policy.ALLOW);
|
||||||
|
holder.notificationSwitch.setChecked(policy.notification);
|
||||||
|
holder.loggingSwitch.setChecked(policy.logging);
|
||||||
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
// Hide for now
|
||||||
policyList.remove(position);
|
holder.moreInfo.setVisibility(View.GONE);
|
||||||
dbHelper.deletePolicy(policy);
|
|
||||||
onBindViewHolder(holder, position);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,18 +6,30 @@ import android.database.Cursor;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
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.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SuDatabaseHelper extends SQLiteOpenHelper {
|
public class SuDatabaseHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
private static final int DATABASE_VER = 1;
|
private static final int DATABASE_VER = 2;
|
||||||
private static final String TABLE_NAME = "policies";
|
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) {
|
public SuDatabaseHelper(Context context) {
|
||||||
super(context, "su.db", null, DATABASE_VER);
|
super(context, "su.db", null, DATABASE_VER);
|
||||||
|
magiskManager = Utils.getMagiskManager(context);
|
||||||
|
pm = context.getPackageManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -28,29 +40,78 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
if (oldVersion == 0) {
|
if (oldVersion == 0) {
|
||||||
db.execSQL(
|
createTables(db);
|
||||||
"CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " " +
|
oldVersion = 2;
|
||||||
"(uid INT, package_name TEXT, app_name TEXT, policy INT, " +
|
}
|
||||||
"until INT, logging INT, notification INT, " +
|
if (oldVersion == 1) {
|
||||||
"PRIMARY KEY(uid))");
|
// 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();
|
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();
|
db.close();
|
||||||
return getPolicy(policy.packageName) == null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Policy getPolicy(int uid) {
|
public Policy getPolicy(int uid) {
|
||||||
Policy policy = null;
|
Policy policy = null;
|
||||||
SQLiteDatabase db = getReadableDatabase();
|
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()) {
|
if (c.moveToNext()) {
|
||||||
policy = new Policy(c);
|
policy = new Policy(c, pm);
|
||||||
}
|
}
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
deletePolicy(uid);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
db.close();
|
db.close();
|
||||||
return policy;
|
return policy;
|
||||||
@ -59,10 +120,13 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
public Policy getPolicy(String pkg) {
|
public Policy getPolicy(String pkg) {
|
||||||
Policy policy = null;
|
Policy policy = null;
|
||||||
SQLiteDatabase db = getReadableDatabase();
|
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()) {
|
if (c.moveToNext()) {
|
||||||
policy = new Policy(c);
|
policy = new Policy(c, pm);
|
||||||
}
|
}
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
deletePolicy(pkg);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
db.close();
|
db.close();
|
||||||
return policy;
|
return policy;
|
||||||
@ -70,13 +134,13 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
public void addPolicy(Policy policy) {
|
public void addPolicy(Policy policy) {
|
||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
db.replace(TABLE_NAME, null, policy.getContentValues());
|
db.replace(POLICY_TABLE, null, policy.getContentValues());
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePolicy(Policy policy) {
|
public void updatePolicy(Policy policy) {
|
||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
db.update(TABLE_NAME, policy.getContentValues(), "package_name=?",
|
db.update(POLICY_TABLE, policy.getContentValues(), "package_name=?",
|
||||||
new String[] { policy.packageName });
|
new String[] { policy.packageName });
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@ -86,15 +150,60 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
Policy policy;
|
Policy policy;
|
||||||
// Clear outdated policies
|
// 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()) });
|
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()) {
|
while (c.moveToNext()) {
|
||||||
policy = new Policy(c);
|
policy = new Policy(c, pm);
|
||||||
ret.add(policy);
|
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();
|
db.close();
|
||||||
return ret;
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,21 +5,18 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.superuser.Policy;
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
public class PackageReceiver extends BroadcastReceiver {
|
public class PackageReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
SuDatabaseHelper suDB = new SuDatabaseHelper(context);
|
MagiskManager magiskManager = Utils.getMagiskManager(context);
|
||||||
String pkg = intent.getData().getEncodedSchemeSpecificPart();
|
String pkg = intent.getData().getEncodedSchemeSpecificPart();
|
||||||
Policy policy = suDB.getPolicy(pkg);
|
Policy policy = magiskManager.suDB.getPolicy(pkg);
|
||||||
if (policy == null)
|
if (policy == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MagiskManager magiskManager = Utils.getMagiskManager(context);
|
|
||||||
magiskManager.initSUConfig();
|
magiskManager.initSUConfig();
|
||||||
|
|
||||||
switch (intent.getAction()) {
|
switch (intent.getAction()) {
|
||||||
@ -29,12 +26,12 @@ public class PackageReceiver extends BroadcastReceiver {
|
|||||||
if (uid > 0) {
|
if (uid > 0) {
|
||||||
policy.uid = uid % 100000;
|
policy.uid = uid % 100000;
|
||||||
}
|
}
|
||||||
suDB.updatePolicy(policy);
|
magiskManager.suDB.updatePolicy(policy);
|
||||||
return;
|
return;
|
||||||
case Intent.ACTION_PACKAGE_REMOVED:
|
case Intent.ACTION_PACKAGE_REMOVED:
|
||||||
boolean isUpdate = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
boolean isUpdate = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
||||||
if (!isUpdate || magiskManager.suReauth) {
|
if (!isUpdate || magiskManager.suReauth) {
|
||||||
suDB.deletePolicy(policy);
|
magiskManager.suDB.deletePolicy(policy);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package com.topjohnwu.magisk.superuser;
|
package com.topjohnwu.magisk.superuser;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.database.Cursor;
|
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 INTERACTIVE = 0;
|
||||||
public static final int DENY = 1;
|
public static final int DENY = 1;
|
||||||
public static final int ALLOW = 2;
|
public static final int ALLOW = 2;
|
||||||
@ -15,37 +16,42 @@ public class Policy {
|
|||||||
public long until;
|
public long until;
|
||||||
public boolean logging = true, notification = true;
|
public boolean logging = true, notification = true;
|
||||||
public String packageName, appName;
|
public String packageName, appName;
|
||||||
public PackageInfo info;
|
public ApplicationInfo info;
|
||||||
|
|
||||||
public Policy(int uid, PackageManager pm) throws PackageManager.NameNotFoundException {
|
public Policy(int uid, PackageManager pm) throws PackageManager.NameNotFoundException {
|
||||||
String[] pkgs = pm.getPackagesForUid(uid);
|
String[] pkgs = pm.getPackagesForUid(uid);
|
||||||
if (pkgs != null && pkgs.length > 0) {
|
if (pkgs != null && pkgs.length > 0) {
|
||||||
info = pm.getPackageInfo(pkgs[0], 0);
|
|
||||||
this.uid = uid;
|
this.uid = uid;
|
||||||
packageName = pkgs[0];
|
packageName = pkgs[0];
|
||||||
appName = info.applicationInfo.loadLabel(pm).toString();
|
info = pm.getApplicationInfo(packageName, 0);
|
||||||
|
appName = info.loadLabel(pm).toString();
|
||||||
} else throw new PackageManager.NameNotFoundException();
|
} else throw new PackageManager.NameNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Policy(Cursor c) {
|
public Policy(Cursor c, PackageManager pm) throws PackageManager.NameNotFoundException {
|
||||||
uid = c.getInt(c.getColumnIndex("uid"));
|
uid = c.getInt(c.getColumnIndex("uid"));
|
||||||
packageName = c.getString(c.getColumnIndex("package_name"));
|
packageName = c.getString(c.getColumnIndex("package_name"));
|
||||||
appName = c.getString(c.getColumnIndex("app_name"));
|
|
||||||
policy = c.getInt(c.getColumnIndex("policy"));
|
policy = c.getInt(c.getColumnIndex("policy"));
|
||||||
until = c.getLong(c.getColumnIndex("until"));
|
until = c.getLong(c.getColumnIndex("until"));
|
||||||
logging = c.getInt(c.getColumnIndex("logging")) != 0;
|
logging = c.getInt(c.getColumnIndex("logging")) != 0;
|
||||||
notification = c.getInt(c.getColumnIndex("notification")) != 0;
|
notification = c.getInt(c.getColumnIndex("notification")) != 0;
|
||||||
|
info = pm.getApplicationInfo(packageName, 0);
|
||||||
|
appName = info.loadLabel(pm).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContentValues getContentValues() {
|
public ContentValues getContentValues() {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put("uid", uid);
|
values.put("uid", uid);
|
||||||
values.put("package_name", packageName);
|
values.put("package_name", packageName);
|
||||||
values.put("app_name", appName);
|
|
||||||
values.put("policy", policy);
|
values.put("policy", policy);
|
||||||
values.put("until", until);
|
values.put("until", until);
|
||||||
values.put("logging", logging ? 1 : 0);
|
values.put("logging", logging ? 1 : 0);
|
||||||
values.put("notification", notification ? 1 : 0);
|
values.put("notification", notification ? 1 : 0);
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NonNull Policy policy) {
|
||||||
|
return appName.toLowerCase().compareTo(policy.appName.toLowerCase());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,12 @@ package com.topjohnwu.magisk.superuser;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.database.SuLogDatabaseHelper;
|
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@ -46,12 +45,12 @@ public class SuReceiver extends BroadcastReceiver {
|
|||||||
action = intent.getStringExtra("action");
|
action = intent.getStringExtra("action");
|
||||||
if (action == null) return;
|
if (action == null) return;
|
||||||
|
|
||||||
SuDatabaseHelper suDbHelper = new SuDatabaseHelper(context);
|
policy = magiskManager.suDB.getPolicy(fromUid);
|
||||||
policy = suDbHelper.getPolicy(fromUid);
|
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
try {
|
try {
|
||||||
policy = new Policy(fromUid, context.getPackageManager());
|
policy = new Policy(fromUid, context.getPackageManager());
|
||||||
} catch (Throwable throwable) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,8 +88,7 @@ public class SuReceiver extends BroadcastReceiver {
|
|||||||
log.fromPid = pid;
|
log.fromPid = pid;
|
||||||
log.command = command;
|
log.command = command;
|
||||||
log.date = new Date();
|
log.date = new Date();
|
||||||
SuLogDatabaseHelper logDbHelper = new SuLogDatabaseHelper(context);
|
magiskManager.suDB.addLog(log);
|
||||||
logDbHelper.addLog(log);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,13 +21,9 @@ import com.topjohnwu.magisk.MagiskManager;
|
|||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||||
import com.topjohnwu.magisk.components.Activity;
|
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.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@ -51,7 +47,6 @@ public class SuRequestActivity extends Activity {
|
|||||||
private LocalSocket socket;
|
private LocalSocket socket;
|
||||||
private PackageManager pm;
|
private PackageManager pm;
|
||||||
private MagiskManager magiskManager;
|
private MagiskManager magiskManager;
|
||||||
private SuDatabaseHelper suDB;
|
|
||||||
|
|
||||||
private boolean hasTimeout;
|
private boolean hasTimeout;
|
||||||
private Policy policy;
|
private Policy policy;
|
||||||
@ -64,7 +59,6 @@ public class SuRequestActivity extends Activity {
|
|||||||
|
|
||||||
pm = getPackageManager();
|
pm = getPackageManager();
|
||||||
magiskManager = getApplicationContext();
|
magiskManager = getApplicationContext();
|
||||||
suDB = new SuDatabaseHelper(this);
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
socketPath = intent.getStringExtra("socket");
|
socketPath = intent.getStringExtra("socket");
|
||||||
@ -109,7 +103,7 @@ public class SuRequestActivity extends Activity {
|
|||||||
setContentView(R.layout.activity_request);
|
setContentView(R.layout.activity_request);
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
appIcon.setImageDrawable(policy.info.applicationInfo.loadIcon(pm));
|
appIcon.setImageDrawable(policy.info.loadIcon(pm));
|
||||||
appNameView.setText(policy.appName);
|
appNameView.setText(policy.appName);
|
||||||
packageNameView.setText(policy.packageName);
|
packageNameView.setText(policy.packageName);
|
||||||
|
|
||||||
@ -180,7 +174,7 @@ public class SuRequestActivity extends Activity {
|
|||||||
policy.policy = action;
|
policy.policy = action;
|
||||||
if (time >= 0) {
|
if (time >= 0) {
|
||||||
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
|
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60);
|
||||||
new SuDatabaseHelper(this).addPolicy(policy);
|
magiskManager.suDB.addPolicy(policy);
|
||||||
}
|
}
|
||||||
handleAction();
|
handleAction();
|
||||||
}
|
}
|
||||||
@ -220,7 +214,7 @@ public class SuRequestActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int uid = payload.getAsInteger("uid");
|
int uid = payload.getAsInteger("uid");
|
||||||
policy = suDB.getPolicy(uid);
|
policy = magiskManager.suDB.getPolicy(uid);
|
||||||
if (policy == null) {
|
if (policy == null) {
|
||||||
policy = new Policy(uid, pm);
|
policy = new Policy(uid, pm);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user