diff --git a/src/main/java/com/topjohnwu/magisk/LogFragment.java b/src/main/java/com/topjohnwu/magisk/LogFragment.java index fa0a9b994..e61e275e1 100644 --- a/src/main/java/com/topjohnwu/magisk/LogFragment.java +++ b/src/main/java/com/topjohnwu/magisk/LogFragment.java @@ -10,6 +10,7 @@ import android.view.ViewGroup; import com.topjohnwu.magisk.adapters.TabFragmentAdapter; import com.topjohnwu.magisk.components.Fragment; +import com.topjohnwu.magisk.utils.Const; import butterknife.BindView; import butterknife.ButterKnife; @@ -33,7 +34,9 @@ public class LogFragment extends Fragment { TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager()); - adapter.addTab(new SuLogFragment(), getString(R.string.superuser)); + if (!(Const.USER_ID > 0 && getApplication().multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED)) { + adapter.addTab(new SuLogFragment(), getString(R.string.superuser)); + } adapter.addTab(new MagiskLogFragment(), getString(R.string.magisk)); tab.setupWithViewPager(viewPager); tab.setVisibility(View.VISIBLE); diff --git a/src/main/java/com/topjohnwu/magisk/MagiskManager.java b/src/main/java/com/topjohnwu/magisk/MagiskManager.java index df67eb2a7..35445f809 100644 --- a/src/main/java/com/topjohnwu/magisk/MagiskManager.java +++ b/src/main/java/com/topjohnwu/magisk/MagiskManager.java @@ -39,7 +39,6 @@ public class MagiskManager extends Application { // Info public boolean hasInit = false; - public int userId; public String magiskVersionString; public int magiskVersionCode = -1; public String remoteMagiskVersionString; @@ -95,14 +94,6 @@ public class MagiskManager extends Application { public void onCreate() { super.onCreate(); prefs = PreferenceManager.getDefaultSharedPreferences(this); - userId = getApplicationInfo().uid / 100000; - - 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(); - } // Handle duplicate package if (!getPackageName().equals(Const.ORIG_PKG_NAME)) { @@ -113,11 +104,15 @@ public class MagiskManager extends Application { startActivity(intent); return; } catch (PackageManager.NameNotFoundException ignored) { /* Expected */ } - } else { + } + + suDB = new SuDatabaseHelper(true); + + if (getPackageName().equals(Const.ORIG_PKG_NAME)) { String pkg = suDB.getStrings(Const.Key.SU_REQUESTER, null); if (pkg != null) { suDB.setStrings(Const.Key.SU_REQUESTER, null); - Shell.su_raw("pm uninstall " + pkg); + Utils.uninstallPkg(pkg); } } @@ -216,6 +211,11 @@ public class MagiskManager extends Application { } catch (NumberFormatException e) { keepEnc = false; } + + if (suDB != null) { + suDB.close(); + suDB = new SuDatabaseHelper(); + } } public void setPermissionGrantCallback(Runnable callback) { diff --git a/src/main/java/com/topjohnwu/magisk/MainActivity.java b/src/main/java/com/topjohnwu/magisk/MainActivity.java index c99b47aa6..414460723 100644 --- a/src/main/java/com/topjohnwu/magisk/MainActivity.java +++ b/src/main/java/com/topjohnwu/magisk/MainActivity.java @@ -149,13 +149,13 @@ public class MainActivity extends Activity menu.findItem(R.id.magiskhide).setVisible( Shell.rootAccess() && mm.magiskVersionCode >= 1300 && prefs.getBoolean(Const.Key.MAGISKHIDE, false)); - menu.findItem(R.id.modules).setVisible( + menu.findItem(R.id.modules).setVisible(!mm.prefs.getBoolean(Const.Key.COREONLY, false) && Shell.rootAccess() && mm.magiskVersionCode >= 0); - menu.findItem(R.id.downloads).setVisible(Utils.checkNetworkStatus() && - Shell.rootAccess() && mm.magiskVersionCode >= 0); - menu.setGroupVisible(R.id.second_group, !mm.prefs.getBoolean(Const.Key.COREONLY, false)); + menu.findItem(R.id.downloads).setVisible(!mm.prefs.getBoolean(Const.Key.COREONLY, false) + && Utils.checkNetworkStatus() && Shell.rootAccess() && mm.magiskVersionCode >= 0); menu.findItem(R.id.log).setVisible(Shell.rootAccess()); - menu.findItem(R.id.superuser).setVisible(Shell.rootAccess()); + menu.findItem(R.id.superuser).setVisible(Shell.rootAccess() && + !(Const.USER_ID > 0 && mm.multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED)); } public void navigate(String item) { diff --git a/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index 95d339e37..1919a2762 100644 --- a/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -133,12 +133,12 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { setSummary(); - // Disable dangerous settings in user mode if selected owner manage - if (mm.userId > 0) { + // Disable dangerous settings in secondary user + if (Const.USER_ID > 0) { suCategory.removePreference(multiuserMode); } - // Remove re-authentication option on Android O, it will not work + // Disable re-authentication option on Android O, it will not work if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { reauth.setEnabled(false); reauth.setSummary(R.string.android_o_not_support); @@ -155,9 +155,13 @@ public class SettingsActivity extends Activity implements Topic.Subscriber { generalCatagory.removePreference(hideManager); } + if (!Shell.rootAccess() || (Const.USER_ID > 0 && + mm.multiuserMode == Const.Value.MULTIUSER_MODE_OWNER_MANAGED)) { + prefScreen.removePreference(suCategory); + } + if (!Shell.rootAccess()) { prefScreen.removePreference(magiskCategory); - prefScreen.removePreference(suCategory); generalCatagory.removePreference(hideManager); } else if (mm.magiskVersionCode < 1300) { prefScreen.removePreference(magiskCategory); diff --git a/src/main/java/com/topjohnwu/magisk/SplashActivity.java b/src/main/java/com/topjohnwu/magisk/SplashActivity.java index 774603e84..34d203a27 100644 --- a/src/main/java/com/topjohnwu/magisk/SplashActivity.java +++ b/src/main/java/com/topjohnwu/magisk/SplashActivity.java @@ -15,7 +15,6 @@ import com.topjohnwu.magisk.asyncs.LoadModules; import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.asyncs.UpdateRepos; import com.topjohnwu.magisk.components.Activity; -import com.topjohnwu.magisk.database.SuDatabaseHelper; import com.topjohnwu.magisk.services.UpdateCheckService; import com.topjohnwu.magisk.utils.Const; import com.topjohnwu.magisk.utils.Shell; @@ -68,9 +67,6 @@ public class SplashActivity extends Activity { mm.bootBlock = ret.get(0); } - // Setup suDB - SuDatabaseHelper.setupSuDB(); - // Add update checking service if (Const.Value.UPDATE_SERVICE_VER > mm.prefs.getInt(Const.Key.UPDATE_SERVICE_VER, -1)) { ComponentName service = new ComponentName(this, UpdateCheckService.class); diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java b/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java index 3795d4786..ac1395ee9 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/FlashZip.java @@ -38,7 +38,7 @@ public class FlashZip extends ParallelTask { private boolean unzipAndCheck() throws Exception { ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android", true); - List ret = Utils.readFile(new File(mCachedFile.getParentFile(), "updater-script").getPath()); + List ret = Utils.readFile(new File(mCachedFile.getParentFile(), "updater-script")); return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK"); } diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java b/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java index d1448d63f..0933621f8 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java @@ -14,7 +14,6 @@ import java.io.File; import java.io.FileInputStream; import java.security.SecureRandom; import java.util.List; -import java.util.Locale; import java.util.jar.JarEntry; public class HideManager extends ParallelTask { @@ -130,7 +129,7 @@ public class HideManager extends ParallelTask { mm.suDB.setStrings(Const.Key.SU_REQUESTER, pkg); Utils.dumpPrefs(); - Shell.su_raw("pm uninstall " + Const.ORIG_PKG_NAME); + Utils.uninstallPkg(Const.ORIG_PKG_NAME); return true; } diff --git a/src/main/java/com/topjohnwu/magisk/asyncs/RestoreStockBoot.java b/src/main/java/com/topjohnwu/magisk/asyncs/RestoreImages.java similarity index 94% rename from src/main/java/com/topjohnwu/magisk/asyncs/RestoreStockBoot.java rename to src/main/java/com/topjohnwu/magisk/asyncs/RestoreImages.java index 1d19f73c3..9df543660 100644 --- a/src/main/java/com/topjohnwu/magisk/asyncs/RestoreStockBoot.java +++ b/src/main/java/com/topjohnwu/magisk/asyncs/RestoreImages.java @@ -9,7 +9,7 @@ import com.topjohnwu.magisk.utils.Utils; import java.util.List; -public class RestoreStockBoot extends ParallelTask { +public class RestoreImages extends ParallelTask { @Override protected Boolean doInBackground(Void... voids) { diff --git a/src/main/java/com/topjohnwu/magisk/container/Policy.java b/src/main/java/com/topjohnwu/magisk/container/Policy.java index 24389a96d..d7e9d769c 100644 --- a/src/main/java/com/topjohnwu/magisk/container/Policy.java +++ b/src/main/java/com/topjohnwu/magisk/container/Policy.java @@ -21,7 +21,7 @@ public class Policy implements Comparable{ public Policy(int uid, PackageManager pm) throws PackageManager.NameNotFoundException { String[] pkgs = pm.getPackagesForUid(uid); if (pkgs == null || pkgs.length == 0) throw new PackageManager.NameNotFoundException(); - this.uid = uid % 100000; + this.uid = uid; packageName = pkgs[0]; info = pm.getApplicationInfo(packageName, 0); appName = info.loadLabel(pm).toString(); diff --git a/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java b/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java index 2a4908645..ebb1a2500 100644 --- a/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java +++ b/src/main/java/com/topjohnwu/magisk/database/SuDatabaseHelper.java @@ -15,10 +15,12 @@ import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.container.Policy; import com.topjohnwu.magisk.container.SuLogEntry; +import com.topjohnwu.magisk.utils.Const; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; import java.io.File; +import java.io.IOException; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; @@ -34,78 +36,75 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { private static final String LOG_TABLE = "logs"; private static final String SETTINGS_TABLE = "settings"; private static final String STRINGS_TABLE = "strings"; - - private static String GLOBAL_DB; + private static final File GLOBAL_DB = new File("/data/adb/magisk.db"); private Context mContext; private PackageManager pm; private SQLiteDatabase mDb; - private static Context preProcess() { + private static Context initDB(boolean local) { Context context; + MagiskManager ce = MagiskManager.get(); 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()) { + Context de = ce.createDeviceProtectedStorageContext(); + File deDB = Utils.getDatabasePath(de, DB_NAME); + if (deDB.exists()) { + context = de; + } else if (ce.magiskVersionCode > 1410) { // Migrate DB path - context.moveDatabaseFrom(ce, DB_NAME); + context = de; + de.moveDatabaseFrom(ce, DB_NAME); + } else { + context = ce; } } else { - context = MagiskManager.get(); + context = ce; } - 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 - ); + if (local && db.length() == 0) { + ce.loadMagiskInfo(); + return initDB(false); + } + + // Only care about local db (no shell involved) + if (local) + return context; + + // We need to make sure the global db is setup properly + if (ce.magiskVersionCode >= 1464 && Shell.rootAccess()) { + Shell.su_raw(Utils.fmt("mkdir %s; chmod 700 %s", GLOBAL_DB.getParent(), GLOBAL_DB.getParent())); + if (!Utils.itemExist(GLOBAL_DB)) { + db = context.getDatabasePath(DB_NAME); + Shell.su(Utils.fmt("cp -af %s %s; rm -f %s*", db, GLOBAL_DB, db)); + } + + try { + db.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + // Make sure the global and local db matches + if (!TextUtils.equals(Utils.checkMD5(GLOBAL_DB), Utils.checkMD5(db))) { + Shell.su(Utils.fmt( + "chown 0.0 %s; chmod 666 %s; chcon u:object_r:su_file:s0 %s;" + + "mount -o bind %s %s", + GLOBAL_DB, GLOBAL_DB, GLOBAL_DB, 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)) { - try { - 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(); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - public SuDatabaseHelper() { - this(preProcess()); + this(false); } - public SuDatabaseHelper(Context context) { + public SuDatabaseHelper(boolean local) { + this(initDB(local)); + } + + private SuDatabaseHelper(Context context) { super(context, DB_NAME, null, DATABASE_VER); mContext = context; pm = context.getPackageManager(); @@ -127,44 +126,32 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { } 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"); + db.execSQL(Utils.fmt("ALTER TABLE %s RENAME TO %s_old", POLICY_TABLE)); // 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"); + db.execSQL(Utils.fmt("INSERT INTO %s SELECT " + + "uid, package_name, policy, until, logging, notification FROM %s_old", + POLICY_TABLE, POLICY_TABLE)); + db.execSQL(Utils.fmt("DROP TABLE %s_old", POLICY_TABLE)); - File oldDB = Utils.getDatabasePath(MagiskManager.get(), "sulog.db"); - if (oldDB.exists()) { - migrateLegacyLogList(oldDB, db); - MagiskManager.get().deleteDatabase("sulog.db"); - } + MagiskManager.get().deleteDatabase("sulog.db"); ++oldVersion; } if (oldVersion == 2) { - db.execSQL("UPDATE " + LOG_TABLE + " SET time=time*1000"); + db.execSQL(Utils.fmt("UPDATE %s SET time=time*1000", LOG_TABLE)); ++oldVersion; } if (oldVersion == 3) { - db.execSQL( - "CREATE TABLE IF NOT EXISTS " + STRINGS_TABLE + " " + - "(key TEXT, value TEXT, PRIMARY KEY(key))"); + db.execSQL(Utils.fmt("CREATE TABLE IF NOT EXISTS %s (key TEXT, value TEXT, PRIMARY KEY(key))", STRINGS_TABLE)); ++oldVersion; } if (oldVersion == 4) { - db.execSQL("UPDATE " + POLICY_TABLE + " SET uid=uid%100000"); + db.execSQL(Utils.fmt("UPDATE %s SET uid=uid%%100000", POLICY_TABLE)); ++oldVersion; } - - if (!Utils.itemExist(GLOBAL_DB)) { - // Hard link our DB globally - Shell.su_raw("ln " + getDbFile() + " " + GLOBAL_DB); - } } catch (Exception e) { e.printStackTrace(); onDowngrade(db, DATABASE_VER, 0); @@ -208,15 +195,13 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { private void cleanup() { // Clear outdated policies - mDb.delete(POLICY_TABLE, "until > 0 AND until < ?", - new String[] { String.valueOf(System.currentTimeMillis() / 1000) }); + mDb.delete(POLICY_TABLE, Utils.fmt("until > 0 AND until < ?", System.currentTimeMillis() / 1000), null); // Clear outdated logs - mDb.delete(LOG_TABLE, "time < ?", new String[] { String.valueOf( - System.currentTimeMillis() - MagiskManager.get().suLogTimeout * 86400000) }); + mDb.delete(LOG_TABLE, Utils.fmt("time < ?", System.currentTimeMillis() - MagiskManager.get().suLogTimeout * 86400000), null); } public void deletePolicy(Policy policy) { - deletePolicy(policy.packageName); + deletePolicy(policy.uid); } public void deletePolicy(String pkg) { @@ -224,12 +209,12 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { } public void deletePolicy(int uid) { - mDb.delete(POLICY_TABLE, "uid=?", new String[]{String.valueOf(uid)}); + mDb.delete(POLICY_TABLE, Utils.fmt("uid=%d", uid), null); } public Policy getPolicy(int uid) { Policy policy = null; - try (Cursor c = mDb.query(POLICY_TABLE, null, "uid=?", new String[] { String.valueOf(uid % 100000) }, null, null, null)) { + try (Cursor c = mDb.query(POLICY_TABLE, null, Utils.fmt("uid=%d", uid), null, null, null, null)) { if (c.moveToNext()) { policy = new Policy(c, pm); } @@ -240,30 +225,17 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { return policy; } - public Policy getPolicy(String pkg) { - Policy policy = null; - try (Cursor c = mDb.query(POLICY_TABLE, null, "package_name=?", new String[] { pkg }, null, null, null)) { - if (c.moveToNext()) { - policy = new Policy(c, pm); - } - } catch (PackageManager.NameNotFoundException e) { - deletePolicy(pkg); - return null; - } - return policy; - } - public void addPolicy(Policy policy) { mDb.replace(POLICY_TABLE, null, policy.getContentValues()); } public void updatePolicy(Policy policy) { - mDb.update(POLICY_TABLE, policy.getContentValues(), "package_name=?", - new String[] { policy.packageName }); + mDb.update(POLICY_TABLE, policy.getContentValues(), Utils.fmt("uid=%d", policy.uid), null); } public List getPolicyList(PackageManager pm) { - try (Cursor c = mDb.query(POLICY_TABLE, null, null, null, null, null, null)) { + try (Cursor c = mDb.query(POLICY_TABLE, null, Utils.fmt("uid/100000=%d", Const.USER_ID), + null, null, null, null)) { List ret = new ArrayList<>(c.getCount()); while (c.moveToNext()) { try { @@ -280,7 +252,8 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { } public List> getLogStructure() { - try (Cursor c = mDb.query(LOG_TABLE, new String[] { "time" }, null, null, null, null, "time DESC")) { + try (Cursor c = mDb.query(LOG_TABLE, new String[] { "time" }, Utils.fmt("from_uid/100000=%d", Const.USER_ID), + null, null, null, "time DESC")) { List> ret = new ArrayList<>(); List list = null; String dateString = null, newString; @@ -299,22 +272,8 @@ public class SuDatabaseHelper extends SQLiteOpenHelper { } public Cursor getLogCursor() { - return getLogCursor(mDb); - } - - public Cursor getLogCursor(SQLiteDatabase db) { - return db.query(LOG_TABLE, null, null, null, null, null, "time DESC"); - } - - private void migrateLegacyLogList(File oldDB, SQLiteDatabase newDB) { - try (SQLiteDatabase oldDb = SQLiteDatabase.openDatabase(oldDB.getPath(), null, SQLiteDatabase.OPEN_READWRITE); - Cursor c = getLogCursor(oldDb)) { - while (c.moveToNext()) { - ContentValues values = new ContentValues(); - DatabaseUtils.cursorRowToContentValues(c, values); - newDB.insert(LOG_TABLE, null, values); - } - } + return mDb.query(LOG_TABLE, null, Utils.fmt("from_uid/100000=%d", Const.USER_ID), + null, null, null, "time DESC"); } public void addLog(SuLogEntry log) { diff --git a/src/main/java/com/topjohnwu/magisk/utils/Const.java b/src/main/java/com/topjohnwu/magisk/utils/Const.java index 81c2c5811..e2cdd0ec9 100644 --- a/src/main/java/com/topjohnwu/magisk/utils/Const.java +++ b/src/main/java/com/topjohnwu/magisk/utils/Const.java @@ -1,6 +1,7 @@ package com.topjohnwu.magisk.utils; import android.os.Environment; +import android.os.Process; import java.io.File; import java.util.Arrays; @@ -63,6 +64,8 @@ public class Const { "com.nianticlabs.pokemongo" ); + public static final int USER_ID = Process.myUid() / 100000; + public static class ID { public static final int UPDATE_SERVICE_ID = 1; public static final int FETCH_ZIP = 2; diff --git a/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java b/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java index 73f65ed6a..3eccf5e5d 100644 --- a/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java +++ b/src/main/java/com/topjohnwu/magisk/utils/ShowUI.java @@ -7,6 +7,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Handler; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; import android.support.v7.app.AlertDialog; @@ -16,14 +17,13 @@ import com.topjohnwu.magisk.FlashActivity; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.SplashActivity; -import com.topjohnwu.magisk.asyncs.RestoreStockBoot; +import com.topjohnwu.magisk.asyncs.RestoreImages; import com.topjohnwu.magisk.components.AlertDialogBuilder; import com.topjohnwu.magisk.receivers.DownloadReceiver; import com.topjohnwu.magisk.receivers.ManagerUpdate; import com.topjohnwu.magisk.receivers.RebootReceiver; -import java.io.File; -import java.io.FileOutputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -258,42 +258,35 @@ public class ShowUI { .setTitle(R.string.uninstall_magisk_title) .setMessage(R.string.uninstall_magisk_msg) .setPositiveButton(R.string.complete_uninstall, (d, i) -> { - try { - InputStream in = mm.getAssets().open(Const.UNINSTALLER); - File uninstaller = new File(mm.getCacheDir(), Const.UNINSTALLER); - FileOutputStream out = new FileOutputStream(uninstaller); - byte[] bytes = new byte[1024]; - int read; - while ((read = in.read(bytes)) != -1) { - out.write(bytes, 0, read); - } - in.close(); - out.close(); - in = mm.getAssets().open(Const.UTIL_FUNCTIONS); - File utils = new File(mm.getCacheDir(), Const.UTIL_FUNCTIONS); - out = new FileOutputStream(utils); - while ((read = in.read(bytes)) != -1) { - out.write(bytes, 0, read); - } - in.close(); - out.close(); - Shell.su( - "cat " + uninstaller + " > /cache/" + Const.UNINSTALLER, - "cat " + utils + " > /data/magisk/" + Const.UTIL_FUNCTIONS - ); - MagiskManager.toast(R.string.uninstall_toast, Toast.LENGTH_LONG); - Shell.su_raw( - "sleep 5", - "pm uninstall " + mm.getApplicationInfo().packageName - ); + ByteArrayOutputStream uninstaller = new ByteArrayOutputStream(); + try (InputStream in = mm.getAssets().open(Const.UNINSTALLER)) { + Utils.inToOut(in, uninstaller); } catch (IOException e) { e.printStackTrace(); + return; } + ByteArrayOutputStream utils = new ByteArrayOutputStream(); + try (InputStream in = mm.getAssets().open(Const.UTIL_FUNCTIONS)) { + Utils.inToOut(in, utils); + } catch (IOException e) { + e.printStackTrace(); + return; + } + + Shell.su( + Utils.fmt("echo '%s' > /cache/%s", uninstaller.toString().replace("'", "'\\''"), Const.UNINSTALLER), + Utils.fmt("echo '%s' > /data/magisk/%s", utils.toString().replace("'", "'\\''"), Const.UTIL_FUNCTIONS) + ); + try { + uninstaller.close(); + utils.close(); + } catch (IOException ignored) {} + + MagiskManager.toast(R.string.uninstall_toast, Toast.LENGTH_LONG); + new Handler().postDelayed(() -> Utils.uninstallPkg(mm.getPackageName()), 5000); }) - .setNeutralButton(R.string.restore_stock_boot, (d, i) -> { - new RestoreStockBoot().exec(); - }) - .setNegativeButton(R.string.no_thanks, null) + .setNeutralButton(R.string.restore_img, (d, i) -> new RestoreImages().exec()) + .setNegativeButton(R.string.uninstall_app, (d, i) -> Utils.uninstallPkg(mm.getPackageName())) .show(); } } diff --git a/src/main/java/com/topjohnwu/magisk/utils/Utils.java b/src/main/java/com/topjohnwu/magisk/utils/Utils.java index e362a635f..bdf1eb7c7 100644 --- a/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -45,24 +45,32 @@ public class Utils { public static boolean isDownloading = false; - public static boolean itemExist(String path) { + public static boolean itemExist(Object path) { List ret = Shell.su(fmt("[ -e %s ] && echo true || echo false", path)); return isValidShellResponse(ret) && Boolean.parseBoolean(ret.get(0)); } - public static void createFile(String path) { - String folder = path.substring(0, path.lastIndexOf('/')); - Shell.su_raw(fmt("mkdir -p %s 2>/dev/null; touch %s 2>/dev/null", folder, path)); + public static void createFile(Object path) { + Shell.su_raw(fmt("mkdir -p `dirname '%s'` 2>/dev/null; touch '%s' 2>/dev/null", path, path)); } - public static void removeItem(String path) { + public static void removeItem(Object path) { Shell.su_raw(fmt("rm -rf %s 2>/dev/null", path)); } - public static List readFile(String path) { + public static List readFile(Object path) { return Shell.su(fmt("cat %s | sed '$a\\ ' | sed '$d'", path)); } + public static String checkMD5(Object path) { + List ret = Shell.su(fmt("md5sum %s", path)); + return isValidShellResponse(ret) ? ret.get(0).split("\\s+")[0] : null; + } + + public static void uninstallPkg(String pkg) { + Shell.su_raw(fmt("find /data/user*/*/%s -exec umount -l {} 2>/dev/null \\;; pm uninstall %s", pkg, pkg)); + } + public static void dlAndReceive(Context context, DownloadReceiver receiver, String link, String filename) { if (isDownloading) return; @@ -209,6 +217,10 @@ public class Utils { } } + public static File getDatabasePath(String dbName) { + return getDatabasePath(MagiskManager.get(), dbName); + } + public static File getDatabasePath(Context context, String dbName) { return new File(context.getFilesDir().getParent() + "/databases", dbName); } @@ -258,7 +270,7 @@ public class Utils { } public static void loadPrefs() { - String config = fmt("/data/user/%d/%s", MagiskManager.get().userId, Const.MANAGER_CONFIGS); + String config = fmt("/data/user/%d/%s", Const.USER_ID, Const.MANAGER_CONFIGS); List ret = readFile(config); if (isValidShellResponse(ret)) { removeItem(config); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 50fd6b2eb..846c3adca 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -115,6 +115,8 @@ Select stock boot image dump in .img or .img.tar format Complete Uninstall Restore Stock Boot + Restore Images + Uninstall App Restoration done! Stock backup does not exist! Uninstalling Magisk Manager in 5 seconds, please manually reboot afterwards