From 5880d4a6ec1193b063a19c8471387566f7e3f38b Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Fri, 20 Oct 2017 00:41:44 +0800 Subject: [PATCH] Use global su database --- .../com/topjohnwu/magisk/MagiskManager.java | 141 +++++++++--------- .../magisk/asyncs/InstallMagisk.java | 6 +- .../topjohnwu/magisk/asyncs/ParallelTask.java | 3 - .../magisk/database/SuDatabaseHelper.java | 85 ++++++++++- .../com/topjohnwu/magisk/utils/Utils.java | 16 +- 5 files changed, 159 insertions(+), 92 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java index e47f34c7a..547eb3d9e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java @@ -1,5 +1,6 @@ package com.topjohnwu.magisk; +import android.annotation.SuppressLint; import android.app.Application; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -55,6 +56,7 @@ public class MagiskManager extends Application { public static final String NOTIFICATION_CHANNEL = "magisk_update_notice"; public static final String BUSYBOXPATH = "/dev/magisk/bin"; public static final int UPDATE_SERVICE_ID = 1; + public static final int UPDATE_SERVICE_VER = 1; // Topics public final Topic magiskHideDone = new Topic(); @@ -79,6 +81,8 @@ public class MagiskManager extends Application { public boolean isSuClient = false; public String suVersion = null; public boolean disabled; + public int snet_version; + public int updateServiceVersion; // Data public Map moduleMap; @@ -103,7 +107,6 @@ public class MagiskManager extends Application { public String localeConfig; public int updateChannel; public String bootFormat; - public int snet_version; // Global resources public SharedPreferences prefs; @@ -118,30 +121,16 @@ public class MagiskManager extends Application { weakSelf = new WeakReference<>(this); } - private class LoadLocale extends ParallelTask { - - @Override - protected Void doInBackground(Void... voids) { - locales = Utils.getAvailableLocale(); - return null; - } - - @Override - protected void onPostExecute(Void aVoid) { - localeDone.publish(); - } - } - @Override public void onCreate() { super.onCreate(); prefs = PreferenceManager.getDefaultSharedPreferences(this); - if (getDatabasePath(SuDatabaseHelper.DB_NAME).exists()) { + if (Utils.getDatabasePath(this, SuDatabaseHelper.DB_NAME).exists()) { // Don't migrate yet, wait and check Magisk version suDB = new SuDatabaseHelper(this); } else { - suDB = new SuDatabaseHelper(Utils.getEncContext()); + suDB = new SuDatabaseHelper(); } repoDB = new RepoDatabaseHelper(this); @@ -183,6 +172,7 @@ public class MagiskManager extends Application { updateChannel = Utils.getPrefsInt(prefs, "update_channel", CheckUpdates.STABLE_CHANNEL); bootFormat = prefs.getString("boot_format", ".img"); snet_version = prefs.getInt("snet_version", -1); + updateServiceVersion = prefs.getInt("update_service_version", -1); } public static void toast(String msg, int duration) { @@ -193,44 +183,64 @@ public class MagiskManager extends Application { mHandler.post(() -> Toast.makeText(weakSelf.get(), resId, duration).show()); } + @SuppressLint("StaticFieldLeak") public void startup() { if (started) return; started = true; - boolean hasNetwork = Utils.checkNetworkStatus(); + // Dynamic detect all locales + new ParallelTask() { + @Override + protected Void doInBackground(Void... voids) { + locales = Utils.getAvailableLocale(); + return null; + } + @Override + protected void onPostExecute(Void aVoid) { + localeDone.publish(); + } + }.exec(); + + // Create notification channel on Android O + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL, + getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT); + getSystemService(NotificationManager.class).createNotificationChannel(channel); + } getMagiskInfo(); - // Check if we need to migrate suDB - if (getDatabasePath(SuDatabaseHelper.DB_NAME).exists() && Utils.useFDE(this)) { - if (magiskVersionCode >= 1410) { - suDB.close(); - Context de = createDeviceProtectedStorageContext(); - de.moveDatabaseFrom(this, SuDatabaseHelper.DB_NAME); - suDB = new SuDatabaseHelper(de); - } - } - - new LoadLocale().exec(); - - // Root actions - if (Shell.rootAccess()) { - if (hasNetwork && !Utils.itemExist(BUSYBOXPATH + "/busybox")) { - try { - // Force synchronous, make sure we have busybox to use - new DownloadBusybox().exec().get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - } - + // Magisk working as expected + if (Shell.rootAccess() && magiskVersionCode > 0) { + // Load utility shell scripts try (InputStream in = getAssets().open(Utils.UTIL_FUNCTIONS)) { shell.loadInputStream(in); } catch (IOException e) { e.printStackTrace(); } + LoadModules loadModuleTask = new LoadModules(); + + if (Utils.checkNetworkStatus()) { + // Make sure we have busybox + if (!Utils.itemExist(BUSYBOXPATH + "/busybox")) { + try { + // Force synchronous, make sure we have busybox to use + new DownloadBusybox().exec().get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + } + + // Fire update check + new CheckUpdates().exec(); + + // Add repo update check + loadModuleTask.setCallBack(() -> new UpdateRepos(false).exec()); + } + + // Root shell initialization Shell.su_raw( "export PATH=" + BUSYBOXPATH + ":$PATH", "mount_partitions", @@ -238,13 +248,30 @@ public class MagiskManager extends Application { "find_boot_image", "migrate_boot_backup" ); - - List res = Shell.su("echo \"$BOOTIMAGE\""); - if (Utils.isValidShellResponse(res)) { - bootBlock = res.get(0); + List ret = Shell.su("echo \"$BOOTIMAGE\""); + if (Utils.isValidShellResponse(ret)) { + bootBlock = ret.get(0); } else { blockList = Shell.su("find /dev/block -type b | grep -vE 'dm|ram|loop'"); } + + // Setup suDB + SuDatabaseHelper.setupSuDB(); + + // Add update checking service + if (UPDATE_SERVICE_VER > updateServiceVersion) { + ComponentName service = new ComponentName(this, UpdateCheckService.class); + JobInfo info = new JobInfo.Builder(UPDATE_SERVICE_ID, service) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setPersisted(true) + .setPeriodic(8 * 60 * 60 * 1000) + .build(); + ((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(info); + updateServiceVersion = UPDATE_SERVICE_VER; + } + + // Fire asynctasks + loadModuleTask.exec(); } // Write back default values @@ -264,30 +291,8 @@ public class MagiskManager extends Application { .putString("update_channel", String.valueOf(updateChannel)) .putString("locale", localeConfig) .putString("boot_format", bootFormat) + .putInt("update_service_version", updateServiceVersion) .apply(); - - // Create notification channel on Android O - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL, - getString(R.string.magisk_updates), NotificationManager.IMPORTANCE_DEFAULT); - getSystemService(NotificationManager.class).createNotificationChannel(channel); - } - - LoadModules loadModuleTask = new LoadModules(); - // Start update check job - if (hasNetwork) { - ComponentName service = new ComponentName(this, UpdateCheckService.class); - JobInfo jobInfo = new JobInfo.Builder(UPDATE_SERVICE_ID, service) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) - .setPersisted(true) - .setPeriodic(8 * 60 * 60 * 1000) - .build(); - ((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo); - loadModuleTask.setCallBack(() -> new UpdateRepos(false).exec()); - } - // Fire asynctasks - loadModuleTask.exec(); - } public void getMagiskInfo() { diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java index 75a95a896..ead86f381 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/InstallMagisk.java @@ -74,7 +74,11 @@ public class InstallMagisk extends ParallelTask { protected Boolean doInBackground(Void... voids) { MagiskManager mm = MagiskManager.get(); - File install = new File(Utils.getEncContext().getFilesDir().getParent(), "install"); + File install = new File( + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? + mm.createDeviceProtectedStorageContext() : + mm).getFilesDir().getParent() + , "install"); Shell.sh_raw("rm -rf " + install); List abis = Arrays.asList(Build.SUPPORTED_ABIS); diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/ParallelTask.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/ParallelTask.java index 5f087967d..bd94e6365 100644 --- a/app/src/main/java/com/topjohnwu/magisk/asyncs/ParallelTask.java +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/ParallelTask.java @@ -3,9 +3,6 @@ package com.topjohnwu.magisk.asyncs; import android.app.Activity; import android.os.AsyncTask; -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.utils.Utils; - import java.lang.ref.WeakReference; public abstract class ParallelTask extends AsyncTask { diff --git a/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java b/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java index d1f87bea4..757072abf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java @@ -7,11 +7,13 @@ import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.os.Build; import android.text.TextUtils; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.container.Policy; import com.topjohnwu.magisk.container.SuLogEntry; +import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import java.io.File; @@ -45,13 +47,75 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { private static final String LOG_TABLE = "logs"; private static final String SETTINGS_TABLE = "settings"; - private MagiskManager mm; + private static String GLOBAL_DB; + + private Context mContext; private PackageManager pm; private SQLiteDatabase mDb; + private static Context preProcess() { + Context context; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Context ce = MagiskManager.get(); + context = ce.createDeviceProtectedStorageContext(); + File oldDB = Utils.getDatabasePath(ce, DB_NAME); + if (oldDB.exists()) { + // Migrate DB path + context.moveDatabaseFrom(ce, DB_NAME); + } + } else { + context = MagiskManager.get(); + } + GLOBAL_DB = context.getFilesDir().getParentFile().getParent() + "/magisk.db"; + File db = Utils.getDatabasePath(context, DB_NAME); + if (!db.exists() && Utils.itemExist(GLOBAL_DB)) { + // Migrate global DB to ours + db.getParentFile().mkdirs(); + Shell.su( + "magisk --clone-attr " + context.getFilesDir() + " " + GLOBAL_DB, + "chmod 660 " + GLOBAL_DB, + "ln " + GLOBAL_DB + " " + db + ); + } + return context; + } + + public static void setupSuDB() { + MagiskManager mm = MagiskManager.get(); + // Check if we need to migrate suDB + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mm.magiskVersionCode >= 1410 && + Utils.getDatabasePath(mm, SuDatabaseHelper.DB_NAME).exists()) { + mm.suDB.close(); + mm.suDB = new SuDatabaseHelper(); + } + + File suDbFile = mm.suDB.getDbFile(); + + if (!Utils.itemExist(GLOBAL_DB)) { + // Hard link our DB globally + Shell.su_raw("ln " + suDbFile + " " + GLOBAL_DB); + } + + // Check if we are linked globally + List ret = Shell.sh("ls -l " + suDbFile); + if (Utils.isValidShellResponse(ret)) { + int links = Integer.parseInt(ret.get(0).trim().split("\\s+")[1]); + if (links < 2) { + mm.suDB.close(); + suDbFile.delete(); + new File(suDbFile + "-journal").delete(); + mm.suDB = new SuDatabaseHelper(); + } + } + } + + public SuDatabaseHelper() { + this(preProcess()); + } + public SuDatabaseHelper(Context context) { super(context, DB_NAME, null, DATABASE_VER); - mm = Utils.getMagiskManager(context); + mContext = context; pm = context.getPackageManager(); mDb = getWritableDatabase(); cleanup(); @@ -82,10 +146,10 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { "FROM " + POLICY_TABLE + "_old"); db.execSQL("DROP TABLE " + POLICY_TABLE + "_old"); - File oldDB = mm.getDatabasePath("sulog.db"); + File oldDB = Utils.getDatabasePath(MagiskManager.get(), "sulog.db"); if (oldDB.exists()) { migrateLegacyLogList(oldDB, db); - mm.deleteDatabase("sulog.db"); + MagiskManager.get().deleteDatabase("sulog.db"); } ++oldVersion; } @@ -93,6 +157,15 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { db.execSQL("UPDATE " + LOG_TABLE + " SET time=time*1000"); ++oldVersion; } + + if (!Utils.itemExist(GLOBAL_DB)) { + // Hard link our DB globally + Shell.su_raw("ln " + getDbFile() + " " + GLOBAL_DB); + } + } + + public File getDbFile() { + return mContext.getDatabasePath(DB_NAME); } private void createTables(SQLiteDatabase db) { @@ -121,7 +194,7 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { new String[] { String.valueOf(System.currentTimeMillis() / 1000) }); // Clear outdated logs mDb.delete(LOG_TABLE, "time < ?", new String[] { String.valueOf( - System.currentTimeMillis() - mm.suLogTimeout * 86400000) }); + System.currentTimeMillis() - MagiskManager.get().suLogTimeout * 86400000) }); } public void deletePolicy(Policy policy) { @@ -179,7 +252,7 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { Policy policy = new Policy(c, pm); // The application changed UID for some reason, check user config if (policy.info.uid != policy.uid) { - if (mm.suReauth) { + if (MagiskManager.get().suReauth) { // Reauth required, remove from DB deletePolicy(policy); continue; diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java index 52c6b641b..f4892a8e2 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -3,7 +3,6 @@ package com.topjohnwu.magisk.utils; import android.Manifest; import android.app.Activity; import android.app.DownloadManager; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -13,7 +12,6 @@ import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; -import android.os.Build; import android.os.Environment; import android.provider.OpenableColumns; import android.support.annotation.StringRes; @@ -202,17 +200,7 @@ public class Utils { } } - public static boolean useFDE(Context context) { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N - && context.getSystemService(DevicePolicyManager.class).getStorageEncryptionStatus() - == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER; - } - - public static Context getEncContext() { - Context context = MagiskManager.get(); - if (useFDE(context)) - return context.createDeviceProtectedStorageContext(); - else - return context; + public static File getDatabasePath(Context context, String dbName) { + return new File(context.getFilesDir().getParent() + "/databases", dbName); } } \ No newline at end of file