diff --git a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java index ab7a34124..abb1018d4 100644 --- a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java @@ -1,12 +1,12 @@ package com.topjohnwu.magisk; -import android.support.v7.app.AlertDialog; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; import android.support.v7.widget.Toolbar; import android.text.Html; import android.text.Spanned; diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java index bf7e917e5..ccc70407e 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskHideFragment.java @@ -15,8 +15,8 @@ import android.view.ViewGroup; import android.widget.SearchView; import com.topjohnwu.magisk.adapters.ApplicationAdapter; +import com.topjohnwu.magisk.asyncs.LoadApps; import com.topjohnwu.magisk.components.Fragment; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.CallbackEvent; import com.topjohnwu.magisk.utils.Logger; @@ -50,7 +50,7 @@ public class MagiskHideFragment extends Fragment implements CallbackEvent.Listen PackageManager packageManager = getActivity().getPackageManager(); mSwipeRefreshLayout.setRefreshing(true); - mSwipeRefreshLayout.setOnRefreshListener(() -> new Async.LoadApps(getActivity()).exec()); + mSwipeRefreshLayout.setOnRefreshListener(() -> new LoadApps(getActivity()).exec()); appAdapter = new ApplicationAdapter(packageManager); recyclerView.setAdapter(appAdapter); diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java b/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java index 8523926a9..68b5712bc 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskLogFragment.java @@ -24,8 +24,8 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; +import com.topjohnwu.magisk.asyncs.SerialTask; import com.topjohnwu.magisk.components.Fragment; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; @@ -126,7 +126,7 @@ public class MagiskLogFragment extends Fragment { } } - public class LogManager extends Async.RootTask { + public class LogManager extends SerialTask { int mode; File targetFile; diff --git a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java index 67b99bd93..4c56e25d0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java +++ b/app/src/main/java/com/topjohnwu/magisk/MagiskManager.java @@ -22,6 +22,8 @@ import java.util.List; public class MagiskManager extends Application { public static final String MAGISK_DISABLE_FILE = "/cache/.disable_magisk"; + public static final String MAGISK_HIDE_PATH = "/magisk/.core/magiskhide/"; + public static final String TMP_FOLDER_PATH = "/dev/tmp"; // Events public final CallbackEvent blockDetectionDone = new CallbackEvent<>(); diff --git a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java index 5bf296c23..c0123e102 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ModulesFragment.java @@ -14,9 +14,10 @@ import android.widget.TextView; import com.github.clans.fab.FloatingActionButton; import com.topjohnwu.magisk.adapters.ModulesAdapter; +import com.topjohnwu.magisk.asyncs.FlashZIP; +import com.topjohnwu.magisk.asyncs.LoadModules; import com.topjohnwu.magisk.components.Fragment; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.CallbackEvent; import com.topjohnwu.magisk.utils.Logger; @@ -53,7 +54,7 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener< mSwipeRefreshLayout.setOnRefreshListener(() -> { recyclerView.setVisibility(View.GONE); - new Async.LoadModules(getActivity()).exec(); + new LoadModules(getActivity()).exec(); }); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @@ -86,7 +87,7 @@ public class ModulesFragment extends Fragment implements CallbackEvent.Listener< if (requestCode == FETCH_ZIP_CODE && resultCode == Activity.RESULT_OK && data != null) { // Get the URI of the selected file final Uri uri = data.getData(); - new Async.FlashZIP(getActivity(), uri).exec(); + new FlashZIP(getActivity(), uri).exec(); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java index b84ab1caf..108d415df 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/ReposFragment.java @@ -15,10 +15,11 @@ import android.widget.TextView; import com.topjohnwu.magisk.adapters.ReposAdapter; import com.topjohnwu.magisk.adapters.SimpleSectionedRecyclerViewAdapter; +import com.topjohnwu.magisk.asyncs.LoadRepos; +import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.components.Fragment; import com.topjohnwu.magisk.module.Module; import com.topjohnwu.magisk.module.Repo; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.CallbackEvent; import com.topjohnwu.magisk.utils.Logger; @@ -68,7 +69,7 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener { recyclerView.setVisibility(View.GONE); - new Async.LoadRepos(getActivity()).exec(); + new LoadRepos(getActivity()).exec(); }); if (getApplication().repoLoadDone.isTriggered) { @@ -171,7 +172,7 @@ public class ReposFragment extends Fragment implements CallbackEvent.Listener { + private class FilterApps extends ParallelTask { @Override protected Void doInBackground(String... strings) { String newText = strings[0]; diff --git a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java index 9cbd87f1f..de1710cf9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SettingsActivity.java @@ -13,9 +13,10 @@ import android.support.v7.widget.Toolbar; import android.view.WindowManager; import android.widget.Toast; +import com.topjohnwu.magisk.asyncs.MagiskHide; +import com.topjohnwu.magisk.asyncs.SerialTask; import com.topjohnwu.magisk.components.Activity; import com.topjohnwu.magisk.module.ModuleHelper; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; @@ -151,7 +152,7 @@ public class SettingsActivity extends Activity { break; case "disable": enabled = prefs.getBoolean("disable", false); - new Async.RootTask() { + new SerialTask() { private boolean enable = enabled; @Override protected Void doInBackground(Void... voids) { @@ -167,7 +168,7 @@ public class SettingsActivity extends Activity { break; case "busybox": enabled = prefs.getBoolean("busybox", false); - new Async.RootTask() { + new SerialTask() { private boolean enable = enabled; @Override protected Void doInBackground(Void... voids) { @@ -191,16 +192,16 @@ public class SettingsActivity extends Activity { Utils.getAlertDialogBuilder(getActivity()) .setTitle(R.string.no_magisksu_title) .setMessage(R.string.no_magisksu_msg) - .setPositiveButton(R.string.understand, (dialog, which) -> new Async.MagiskHide().enable()) + .setPositiveButton(R.string.understand, (dialog, which) -> new MagiskHide().enable()) .setCancelable(false) .show(); - } else new Async.MagiskHide().enable(); + } else new MagiskHide().enable(); } else - new Async.MagiskHide().disable(); + new MagiskHide().disable(); break; case "hosts": enabled = prefs.getBoolean("hosts", false); - new Async.RootTask() { + new SerialTask() { private boolean enable = enabled; @Override protected Void doInBackground(Void... voids) { diff --git a/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java b/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java index adb4f3ad4..fe8f71f15 100644 --- a/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/SplashActivity.java @@ -3,8 +3,13 @@ package com.topjohnwu.magisk; import android.content.Intent; import android.os.Bundle; +import com.topjohnwu.magisk.asyncs.CheckUpdates; +import com.topjohnwu.magisk.asyncs.GetBootBlocks; +import com.topjohnwu.magisk.asyncs.LoadApps; +import com.topjohnwu.magisk.asyncs.LoadModules; +import com.topjohnwu.magisk.asyncs.LoadRepos; +import com.topjohnwu.magisk.asyncs.MagiskHide; import com.topjohnwu.magisk.components.Activity; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; @@ -27,20 +32,20 @@ public class SplashActivity extends Activity { boolean started = Utils.isValidShellResponse(ret) && Integer.parseInt(ret.get(0)) != 0; // Now fire all async tasks - new Async.CheckUpdates(this).exec(); - new Async.GetBootBlocks(this).exec(); + new CheckUpdates(this).exec(); + new GetBootBlocks(this).exec(); if (magiskManager.magiskHide && !magiskManager.disabled && magiskManager.magiskVersion > 11 && !started) { - new Async.MagiskHide().enable(); + new MagiskHide().enable(); } - new Async.LoadModules(this) { + new LoadModules(this) { @Override protected void onPostExecute(Void v) { super.onPostExecute(v); - new Async.LoadRepos(activity).exec(); + new LoadRepos(activity).exec(); } }.exec(); - new Async.LoadApps(this).exec(); + new LoadApps(this).exec(); // Preparation done, now start main activity Intent intent = new Intent(getApplicationContext(), MainActivity.class); diff --git a/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java b/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java index 2abc44b7d..1f68af727 100644 --- a/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java +++ b/app/src/main/java/com/topjohnwu/magisk/StatusFragment.java @@ -1,12 +1,12 @@ package com.topjohnwu.magisk; -import android.support.v7.app.AlertDialog; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.FragmentTransaction; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -14,8 +14,8 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.topjohnwu.magisk.asyncs.CheckUpdates; import com.topjohnwu.magisk.components.Fragment; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.CallbackEvent; import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.utils.Shell; @@ -84,7 +84,7 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener { @@ -92,7 +92,7 @@ public class StatusFragment extends Fragment implements CallbackEvent.Listener { if (isChecked) { - new Async.MagiskHide().add(info.packageName); + new MagiskHide().add(info.packageName); mHideList.add(info.packageName); } else { - new Async.MagiskHide().rm(info.packageName); + new MagiskHide().rm(info.packageName); mHideList.remove(info.packageName); } }); diff --git a/app/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java b/app/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java index 6b802b970..c03dc936c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java +++ b/app/src/main/java/com/topjohnwu/magisk/adapters/ModulesAdapter.java @@ -12,8 +12,8 @@ import android.widget.ImageView; import android.widget.TextView; import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.asyncs.SerialTask; import com.topjohnwu.magisk.module.Module; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Shell; import java.util.List; @@ -52,7 +52,7 @@ public class ModulesAdapter extends RecyclerView.Adapter new Async.RootTask() { + holder.checkBox.setOnCheckedChangeListener((v, isChecked) -> new SerialTask() { @Override protected Void doInBackground(Void... voids) { if (isChecked) { @@ -70,7 +70,7 @@ public class ModulesAdapter extends RecyclerView.Adapter new Async.RootTask() { + holder.delete.setOnClickListener(v -> new SerialTask() { private final boolean removed = module.willBeRemoved(); @Override diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java new file mode 100644 index 000000000..efb20c103 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/CheckUpdates.java @@ -0,0 +1,36 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; + +import com.topjohnwu.magisk.utils.WebService; + +import org.json.JSONException; +import org.json.JSONObject; + +public class CheckUpdates extends ParallelTask { + + public static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json"; + + public CheckUpdates(Activity context) { + super(context); + } + + @Override + protected Void doInBackground(Void... voids) { + String jsonStr = WebService.request(UPDATE_JSON, WebService.GET); + try { + JSONObject json = new JSONObject(jsonStr); + JSONObject magisk = json.getJSONObject("magisk"); + magiskManager.remoteMagiskVersion = magisk.getDouble("versionCode"); + magiskManager.magiskLink = magisk.getString("link"); + magiskManager.releaseNoteLink = magisk.getString("note"); + } catch (JSONException ignored) { + } + return null; + } + + @Override + protected void onPostExecute(Void v) { + magiskManager.updateCheckDone.trigger(); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZIP.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZIP.java new file mode 100644 index 000000000..76c7c5603 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/FlashZIP.java @@ -0,0 +1,172 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.database.Cursor; +import android.net.Uri; +import android.provider.OpenableColumns; +import android.widget.Toast; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.utils.Logger; +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; +import com.topjohnwu.magisk.utils.ZipUtils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +public class FlashZIP extends SerialTask { + + protected Uri mUri; + protected File mCachedFile; + + private String mFilename; + private ProgressDialog progress; + + public FlashZIP(Activity context, Uri uri, String filename) { + super(context); + mUri = uri; + mFilename = filename; + } + + public FlashZIP(Activity context, Uri uri) { + super(context); + mUri = uri; + + // Try to get the filename ourselves + Cursor c = magiskManager.getContentResolver().query(uri, null, null, null, null); + if (c != null) { + int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME); + c.moveToFirst(); + if (nameIndex != -1) { + mFilename = c.getString(nameIndex); + } + c.close(); + } + if (mFilename == null) { + int idx = uri.getPath().lastIndexOf('/'); + mFilename = uri.getPath().substring(idx + 1); + } + } + + protected void preProcessing() throws Throwable { + } + + protected void copyToCache() throws Throwable { + publishProgress(magiskManager.getString(R.string.copying_msg)); + mCachedFile = new File(magiskManager.getCacheDir().getAbsolutePath() + "/install.zip"); + if (mCachedFile.exists() && !mCachedFile.delete()) { + Logger.error("FlashZip: Error while deleting already existing file"); + throw new IOException(); + } + try ( + InputStream in = magiskManager.getContentResolver().openInputStream(mUri); + OutputStream outputStream = new FileOutputStream(mCachedFile) + ) { + byte buffer[] = new byte[1024]; + int length; + if (in == null) throw new FileNotFoundException(); + while ((length = in.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath()); + } catch (FileNotFoundException e) { + Logger.error("FlashZip: Invalid Uri"); + throw e; + } catch (IOException e) { + Logger.error("FlashZip: Error in creating file"); + throw e; + } + } + + protected boolean unzipAndCheck() { + ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android"); + List ret; + ret = Utils.readFile(mCachedFile.getParent() + "/META-INF/com/google/android/updater-script"); + return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK"); + } + + @Override + protected void onPreExecute() { + progress = new ProgressDialog(activity); + progress.setTitle(R.string.zip_install_progress_title); + progress.show(); + } + + @Override + protected void onProgressUpdate(String... values) { + progress.setMessage(values[0]); + } + + @Override + protected Integer doInBackground(Void... voids) { + Logger.dev("FlashZip Running... " + mFilename); + List ret; + try { + preProcessing(); + copyToCache(); + } catch (Throwable e) { + e.printStackTrace(); + return -1; + } + if (!unzipAndCheck()) return 0; + publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename)); + ret = Shell.su( + "BOOTMODE=true sh " + mCachedFile.getParent() + + "/META-INF/com/google/android/update-binary dummy 1 " + mCachedFile.getPath(), + "if [ $? -eq 0 ]; then echo true; else echo false; fi" + ); + if (!Utils.isValidShellResponse(ret)) return -1; + Logger.dev("FlashZip: Console log:"); + for (String line : ret) { + Logger.dev(line); + } + Shell.su( + "rm -rf " + mCachedFile.getParent() + "/*", + "rm -rf " + MagiskManager.TMP_FOLDER_PATH + ); + if (Boolean.parseBoolean(ret.get(ret.size() - 1))) { + return 1; + } + return -1; + } + + // -1 = error, manual install; 0 = invalid zip; 1 = success + @Override + protected void onPostExecute(Integer result) { + super.onPostExecute(result); + progress.dismiss(); + switch (result) { + case -1: + Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show(); + Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_1, mUri.getPath()), Toast.LENGTH_LONG).show(); + Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_2), Toast.LENGTH_LONG).show(); + break; + case 0: + Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show(); + break; + case 1: + onSuccess(); + break; + } + } + + protected void onSuccess() { + magiskManager.updateCheckDone.trigger(); + new LoadModules(activity).exec(); + + Utils.getAlertDialogBuilder(activity) + .setTitle(R.string.reboot_title) + .setMessage(R.string.reboot_msg) + .setPositiveButton(R.string.reboot, (dialogInterface, i) -> Shell.su(true, "reboot")) + .setNegativeButton(R.string.no_thanks, null) + .show(); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/GetBootBlocks.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/GetBootBlocks.java new file mode 100644 index 000000000..489467942 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/GetBootBlocks.java @@ -0,0 +1,28 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; + +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; + +public class GetBootBlocks extends SerialTask { + + public GetBootBlocks(Activity context) { + super(context); + } + + @Override + protected Void doInBackground(Void... params) { + if (Shell.rootAccess()) { + magiskManager.blockList = Shell.su("ls /dev/block | grep mmc"); + if (magiskManager.bootBlock == null) + magiskManager.bootBlock = Utils.detectBootImage(); + } + return null; + } + + @Override + protected void onPostExecute(Void v) { + magiskManager.blockDetectionDone.trigger(); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java new file mode 100644 index 000000000..c9c544e01 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadApps.java @@ -0,0 +1,39 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.adapters.ApplicationAdapter; +import com.topjohnwu.magisk.utils.Shell; + +import java.util.Collections; +import java.util.Iterator; + +public class LoadApps extends SerialTask { + + public LoadApps(Activity context) { + super(context); + } + + @Override + protected Void doInBackground(Void... voids) { + PackageManager pm = magiskManager.getPackageManager(); + magiskManager.appList = pm.getInstalledApplications(0); + for (Iterator i = magiskManager.appList.iterator(); i.hasNext(); ) { + ApplicationInfo info = i.next(); + if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) + i.remove(); + } + Collections.sort(magiskManager.appList, (a, b) -> a.loadLabel(pm).toString().toLowerCase() + .compareTo(b.loadLabel(pm).toString().toLowerCase())); + magiskManager.magiskHideList = Shell.su(MagiskManager.MAGISK_HIDE_PATH + "list"); + return null; + } + + @Override + protected void onPostExecute(Void v) { + magiskManager.packageLoadDone.trigger(); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java new file mode 100644 index 000000000..ab4b5cb0d --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadModules.java @@ -0,0 +1,23 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; + +import com.topjohnwu.magisk.module.ModuleHelper; + +public class LoadModules extends SerialTask { + + public LoadModules(Activity context) { + super(context); + } + + @Override + protected Void doInBackground(Void... voids) { + ModuleHelper.createModuleMap(magiskManager); + return null; + } + + @Override + protected void onPostExecute(Void v) { + magiskManager.moduleLoadDone.trigger(); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java new file mode 100644 index 000000000..dde914246 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/LoadRepos.java @@ -0,0 +1,23 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; + +import com.topjohnwu.magisk.module.ModuleHelper; + +public class LoadRepos extends ParallelTask { + + public LoadRepos(Activity context) { + super(context); + } + + @Override + protected Void doInBackground(Void... voids) { + ModuleHelper.createRepoMap(magiskManager); + return null; + } + + @Override + protected void onPostExecute(Void v) { + magiskManager.repoLoadDone.trigger(); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/MagiskHide.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/MagiskHide.java new file mode 100644 index 000000000..9f65c866a --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/MagiskHide.java @@ -0,0 +1,31 @@ +package com.topjohnwu.magisk.asyncs; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.utils.Shell; + +public class MagiskHide extends SerialTask { + + @Override + protected Void doInBackground(Object... params) { + String command = (String) params[0]; + Shell.su(MagiskManager.MAGISK_HIDE_PATH + command); + return null; + } + + public void add(CharSequence packageName) { + exec("add " + packageName); + } + + public void rm(CharSequence packageName) { + exec("rm " + packageName); + } + + public void enable() { + exec("enable; setprop persist.magisk.hide 1"); + } + + public void disable() { + exec("disable; setprop persist.magisk.hide 0"); + } + +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/ParallelTask.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/ParallelTask.java new file mode 100644 index 000000000..6779d6cb2 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/ParallelTask.java @@ -0,0 +1,24 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; +import android.os.AsyncTask; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.utils.Utils; + +public abstract class ParallelTask extends AsyncTask { + protected Activity activity; + protected MagiskManager magiskManager; + + public ParallelTask() {} + + public ParallelTask(Activity context) { + activity = context; + magiskManager = Utils.getMagiskManager(context); + } + + @SafeVarargs + public final void exec(Params... params) { + executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/asyncs/SerialTask.java b/app/src/main/java/com/topjohnwu/magisk/asyncs/SerialTask.java new file mode 100644 index 000000000..825fbbf41 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/asyncs/SerialTask.java @@ -0,0 +1,30 @@ +package com.topjohnwu.magisk.asyncs; + +import android.app.Activity; +import android.os.AsyncTask; + +import com.topjohnwu.magisk.MagiskManager; +import com.topjohnwu.magisk.utils.Shell; +import com.topjohnwu.magisk.utils.Utils; + +/** + * This class is only used for running root commands + **/ + +public abstract class SerialTask extends AsyncTask { + protected Activity activity; + protected MagiskManager magiskManager; + + public SerialTask() {} + + public SerialTask(Activity context) { + activity = context; + magiskManager = Utils.getMagiskManager(context); + } + + @SafeVarargs + public final void exec(Params... params) { + if (!Shell.rootAccess()) return; + executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params); + } +} diff --git a/app/src/main/java/com/topjohnwu/magisk/module/ModuleHelper.java b/app/src/main/java/com/topjohnwu/magisk/module/ModuleHelper.java index ad942684c..2ee230a66 100644 --- a/app/src/main/java/com/topjohnwu/magisk/module/ModuleHelper.java +++ b/app/src/main/java/com/topjohnwu/magisk/module/ModuleHelper.java @@ -9,7 +9,7 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Async; +import com.topjohnwu.magisk.asyncs.LoadRepos; import com.topjohnwu.magisk.utils.Logger; import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.ValueSortedMap; @@ -151,7 +151,7 @@ public class ModuleHelper { .remove(VERSION_KEY) .apply(); magiskManager.repoLoadDone.isTriggered = false; - new Async.LoadRepos(activity).exec(); + new LoadRepos(activity).exec(); Toast.makeText(activity, R.string.repo_cache_cleared, Toast.LENGTH_SHORT).show(); } diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/BootReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/BootReceiver.java index c360e1ad5..858dc5c86 100644 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/BootReceiver.java +++ b/app/src/main/java/com/topjohnwu/magisk/receivers/BootReceiver.java @@ -8,7 +8,6 @@ import android.widget.Toast; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.Utils; @@ -37,7 +36,7 @@ public class BootReceiver extends BroadcastReceiver { if (magiskManager.prefs.getBoolean("magiskhide", false) && !magiskManager.disabled && !started && magiskManager.magiskVersion > 11) { magiskManager.toast(R.string.start_magiskhide, Toast.LENGTH_LONG); - Shell.su(true, Async.MAGISK_HIDE_PATH + "enable", + Shell.su(true, MagiskManager.MAGISK_HIDE_PATH + "enable", "setprop persist.magisk.hide 1"); } } diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/MagiskDlReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/MagiskDlReceiver.java index f6be0eb2e..54e99a371 100644 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/MagiskDlReceiver.java +++ b/app/src/main/java/com/topjohnwu/magisk/receivers/MagiskDlReceiver.java @@ -4,7 +4,8 @@ import android.net.Uri; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Async; +import com.topjohnwu.magisk.asyncs.FlashZIP; +import com.topjohnwu.magisk.asyncs.SerialTask; import com.topjohnwu.magisk.utils.Shell; import com.topjohnwu.magisk.utils.ZipUtils; @@ -23,7 +24,7 @@ public class MagiskDlReceiver extends DownloadReceiver { @Override public void onDownloadDone(Uri uri) { - new Async.FlashZIP(activity, uri, mFilename) { + new FlashZIP(activity, uri, mFilename) { @Override protected void preProcessing() throws Throwable { @@ -42,8 +43,8 @@ public class MagiskDlReceiver extends DownloadReceiver { // We will have complete busybox after Magisk installation ZipUtils.unzip(mCachedFile, new File(mCachedFile.getParent(), "magisk")); Shell.su( - "mkdir -p " + Async.TMP_FOLDER_PATH + "/magisk", - "cp -af " + mCachedFile.getParent() + "/magisk/. " + Async.TMP_FOLDER_PATH + "/magisk", + "mkdir -p " + MagiskManager.TMP_FOLDER_PATH + "/magisk", + "cp -af " + mCachedFile.getParent() + "/magisk/. " + MagiskManager.TMP_FOLDER_PATH + "/magisk", "mv -f " + mCachedFile.getParent() + "/magisk/META-INF " + mCachedFile.getParent() + "/META-INF" ); } @@ -52,7 +53,7 @@ public class MagiskDlReceiver extends DownloadReceiver { @Override protected void onSuccess() { - new Async.RootTask() { + new SerialTask() { @Override protected Void doInBackground(Void... params) { Shell.su("setprop magisk.version " diff --git a/app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java b/app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java index c402c3681..37b5a360c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java +++ b/app/src/main/java/com/topjohnwu/magisk/receivers/RepoDlReceiver.java @@ -3,7 +3,7 @@ package com.topjohnwu.magisk.receivers; import android.net.Uri; import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.utils.Async; +import com.topjohnwu.magisk.asyncs.FlashZIP; import com.topjohnwu.magisk.utils.ByteArrayInOutStream; import com.topjohnwu.magisk.utils.ZipUtils; @@ -13,7 +13,7 @@ public class RepoDlReceiver extends DownloadReceiver { @Override public void onDownloadDone(Uri uri) { // Flash the zip - new Async.FlashZIP(activity, uri, mFilename){ + new FlashZIP(activity, uri, mFilename){ @Override protected void preProcessing() throws Throwable { // Process and sign the zip diff --git a/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java b/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java index 0e2ea8446..0ca5368b3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java +++ b/app/src/main/java/com/topjohnwu/magisk/superuser/SuRequestActivity.java @@ -19,8 +19,8 @@ import android.widget.TextView; import com.topjohnwu.magisk.MagiskManager; import com.topjohnwu.magisk.R; +import com.topjohnwu.magisk.asyncs.ParallelTask; import com.topjohnwu.magisk.components.Activity; -import com.topjohnwu.magisk.utils.Async; import com.topjohnwu.magisk.utils.CallbackEvent; import java.io.DataInputStream; @@ -167,7 +167,7 @@ public class SuRequestActivity extends Activity implements CallbackEvent.Listene } } - private class SocketManager extends Async.NormalTask { + private class SocketManager extends ParallelTask { @Override protected Boolean doInBackground(Void... params) { diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java b/app/src/main/java/com/topjohnwu/magisk/utils/Async.java deleted file mode 100644 index 499ff741b..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Async.java +++ /dev/null @@ -1,363 +0,0 @@ -package com.topjohnwu.magisk.utils; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.net.Uri; -import android.os.AsyncTask; -import android.provider.OpenableColumns; -import android.widget.Toast; - -import com.topjohnwu.magisk.MagiskManager; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.adapters.ApplicationAdapter; -import com.topjohnwu.magisk.module.ModuleHelper; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -public class Async { - - public abstract static class RootTask extends AsyncTask { - protected Activity activity; - protected MagiskManager magiskManager; - - public RootTask() {} - - public RootTask(Activity context) { - activity = context; - magiskManager = Utils.getMagiskManager(context); - } - @SafeVarargs - public final void exec(Params... params) { - if (!Shell.rootAccess()) return; - executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params); - } - } - - public abstract static class NormalTask extends AsyncTask { - protected Activity activity; - protected MagiskManager magiskManager; - - public NormalTask() {} - - public NormalTask(Activity context) { - activity = context; - magiskManager = Utils.getMagiskManager(context); - } - @SafeVarargs - public final void exec(Params... params) { - executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); - } - } - - public static final String UPDATE_JSON = "https://raw.githubusercontent.com/topjohnwu/MagiskManager/updates/magisk_update.json"; - public static final String MAGISK_HIDE_PATH = "/magisk/.core/magiskhide/"; - public static final String TMP_FOLDER_PATH = "/dev/tmp"; - - public static class CheckUpdates extends NormalTask { - - public CheckUpdates(Activity context) { - super(context); - } - - @Override - protected Void doInBackground(Void... voids) { - String jsonStr = WebService.request(UPDATE_JSON, WebService.GET); - try { - JSONObject json = new JSONObject(jsonStr); - JSONObject magisk = json.getJSONObject("magisk"); - magiskManager.remoteMagiskVersion = magisk.getDouble("versionCode"); - magiskManager.magiskLink = magisk.getString("link"); - magiskManager.releaseNoteLink = magisk.getString("note"); - } catch (JSONException ignored) {} - return null; - } - - @Override - protected void onPostExecute(Void v) { - magiskManager.updateCheckDone.trigger(); - } - } - - public static void checkSafetyNet(MagiskManager magiskManager) { - new SafetyNetHelper(magiskManager) { - @Override - public void handleResults(int i) { - magiskManager.SNCheckResult = i; - magiskManager.safetyNetDone.trigger(); - } - }.requestTest(); - } - - public static class LoadModules extends RootTask { - - public LoadModules(Activity context) { - super(context); - } - - @Override - protected Void doInBackground(Void... voids) { - ModuleHelper.createModuleMap(magiskManager); - return null; - } - - @Override - protected void onPostExecute(Void v) { - magiskManager.moduleLoadDone.trigger(); - } - } - - public static class LoadRepos extends NormalTask { - - public LoadRepos(Activity context) { - super(context); - } - - @Override - protected Void doInBackground(Void... voids) { - ModuleHelper.createRepoMap(magiskManager); - return null; - } - - @Override - protected void onPostExecute(Void v) { - magiskManager.repoLoadDone.trigger(); - } - } - - public static class LoadApps extends RootTask { - - public LoadApps(Activity context) { - super(context); - } - - @Override - protected Void doInBackground(Void... voids) { - PackageManager pm = magiskManager.getPackageManager(); - magiskManager.appList = pm.getInstalledApplications(0); - for (Iterator i = magiskManager.appList.iterator(); i.hasNext(); ) { - ApplicationInfo info = i.next(); - if (ApplicationAdapter.BLACKLIST.contains(info.packageName) || !info.enabled) - i.remove(); - } - Collections.sort(magiskManager.appList, (a, b) -> a.loadLabel(pm).toString().toLowerCase() - .compareTo(b.loadLabel(pm).toString().toLowerCase())); - magiskManager.magiskHideList = Shell.su(Async.MAGISK_HIDE_PATH + "list"); - return null; - } - - @Override - protected void onPostExecute(Void v) { - magiskManager.packageLoadDone.trigger(); - } - } - - public static class FlashZIP extends RootTask { - - protected Uri mUri; - protected File mCachedFile; - private String mFilename; - protected ProgressDialog progress; - - public FlashZIP(Activity context, Uri uri, String filename) { - super(context); - mUri = uri; - mFilename = filename; - } - - public FlashZIP(Activity context, Uri uri) { - super(context); - mUri = uri; - - // Try to get the filename ourselves - Cursor c = magiskManager.getContentResolver().query(uri, null, null, null, null); - if (c != null) { - int nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME); - c.moveToFirst(); - if (nameIndex != -1) { - mFilename = c.getString(nameIndex); - } - c.close(); - } - if (mFilename == null) { - int idx = uri.getPath().lastIndexOf('/'); - mFilename = uri.getPath().substring(idx + 1); - } - } - - protected void preProcessing() throws Throwable {} - - protected void copyToCache() throws Throwable { - publishProgress(magiskManager.getString(R.string.copying_msg)); - mCachedFile = new File(magiskManager.getCacheDir().getAbsolutePath() + "/install.zip"); - if (mCachedFile.exists() && !mCachedFile.delete()) { - Logger.error("FlashZip: Error while deleting already existing file"); - throw new IOException(); - } - try ( - InputStream in = magiskManager.getContentResolver().openInputStream(mUri); - OutputStream outputStream = new FileOutputStream(mCachedFile) - ) { - byte buffer[] = new byte[1024]; - int length; - if (in == null) throw new FileNotFoundException(); - while ((length = in.read(buffer)) > 0) { - outputStream.write(buffer, 0, length); - } - Logger.dev("FlashZip: File created successfully - " + mCachedFile.getPath()); - } catch (FileNotFoundException e) { - Logger.error("FlashZip: Invalid Uri"); - throw e; - } catch (IOException e) { - Logger.error("FlashZip: Error in creating file"); - throw e; - } - } - - protected boolean unzipAndCheck() { - ZipUtils.unzip(mCachedFile, mCachedFile.getParentFile(), "META-INF/com/google/android"); - List ret; - ret = Utils.readFile(mCachedFile.getParent() + "/META-INF/com/google/android/updater-script"); - return Utils.isValidShellResponse(ret) && ret.get(0).contains("#MAGISK"); - } - - @Override - protected void onPreExecute() { - progress = new ProgressDialog(activity); - progress.setTitle(R.string.zip_install_progress_title); - progress.show(); - } - - @Override - protected void onProgressUpdate(String... values) { - progress.setMessage(values[0]); - } - - @Override - protected Integer doInBackground(Void... voids) { - Logger.dev("FlashZip Running... " + mFilename); - List ret; - try { - preProcessing(); - copyToCache(); - } catch (Throwable e) { - e.printStackTrace(); - return -1; - } - if (!unzipAndCheck()) return 0; - publishProgress(magiskManager.getString(R.string.zip_install_progress_msg, mFilename)); - ret = Shell.su( - "BOOTMODE=true sh " + mCachedFile.getParent() + - "/META-INF/com/google/android/update-binary dummy 1 " + mCachedFile.getPath(), - "if [ $? -eq 0 ]; then echo true; else echo false; fi" - ); - if (!Utils.isValidShellResponse(ret)) return -1; - Logger.dev("FlashZip: Console log:"); - for (String line : ret) { - Logger.dev(line); - } - Shell.su( - "rm -rf " + mCachedFile.getParent() + "/*", - "rm -rf " + TMP_FOLDER_PATH - ); - if (Boolean.parseBoolean(ret.get(ret.size() - 1))) { - return 1; - } - return -1; - } - - // -1 = error, manual install; 0 = invalid zip; 1 = success - @Override - protected void onPostExecute(Integer result) { - super.onPostExecute(result); - progress.dismiss(); - switch (result) { - case -1: - Toast.makeText(magiskManager, magiskManager.getString(R.string.install_error), Toast.LENGTH_LONG).show(); - Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_1, mUri.getPath()), Toast.LENGTH_LONG).show(); - Toast.makeText(magiskManager, magiskManager.getString(R.string.manual_install_2), Toast.LENGTH_LONG).show(); - break; - case 0: - Toast.makeText(magiskManager, magiskManager.getString(R.string.invalid_zip), Toast.LENGTH_LONG).show(); - break; - case 1: - onSuccess(); - break; - } - } - - protected void onSuccess() { - magiskManager.updateCheckDone.trigger(); - new LoadModules(activity).exec(); - - Utils.getAlertDialogBuilder(activity) - .setTitle(R.string.reboot_title) - .setMessage(R.string.reboot_msg) - .setPositiveButton(R.string.reboot, (dialogInterface, i) -> Shell.su(true, "reboot")) - .setNegativeButton(R.string.no_thanks, null) - .show(); - } - } - - public static class MagiskHide extends RootTask { - - @Override - protected Void doInBackground(Object... params) { - String command = (String) params[0]; - Shell.su(MAGISK_HIDE_PATH + command); - return null; - } - - public void add(CharSequence packageName) { - exec("add " + packageName); - } - - public void rm(CharSequence packageName) { - exec("rm " + packageName); - } - - public void enable() { - exec("enable; setprop persist.magisk.hide 1"); - } - - public void disable() { - exec("disable; setprop persist.magisk.hide 0"); - } - - } - - public static class GetBootBlocks extends RootTask { - - public GetBootBlocks(Activity context) { - super(context); - } - - @Override - protected Void doInBackground(Void... params) { - if (Shell.rootAccess()) { - magiskManager.blockList = Shell.su("ls /dev/block | grep mmc"); - if (magiskManager.bootBlock == null) - magiskManager.bootBlock = Utils.detectBootImage(); - } - return null; - } - - @Override - protected void onPostExecute(Void v) { - magiskManager.blockDetectionDone.trigger(); - } - } -} 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 628d9a486..bc0588f78 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/Utils.java @@ -66,9 +66,8 @@ public class Utils { } public static void dlAndReceive(Context context, DownloadReceiver receiver, String link, String filename) { - if (isDownloading) { + if (isDownloading) return; - } if (ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { Toast.makeText(context, R.string.permissionNotGranted, Toast.LENGTH_LONG).show(); @@ -144,4 +143,13 @@ public class Utils { return (MagiskManager) context.getApplicationContext(); } + public static void checkSafetyNet(MagiskManager magiskManager) { + new SafetyNetHelper(magiskManager) { + @Override + public void handleResults(int i) { + magiskManager.SNCheckResult = i; + magiskManager.safetyNetDone.trigger(); + } + }.requestTest(); + } } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java b/app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java index 089f2549f..c8d55e746 100644 --- a/app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java +++ b/app/src/main/java/com/topjohnwu/magisk/utils/WebWindow.java @@ -1,7 +1,7 @@ package com.topjohnwu.magisk.utils; -import android.support.v7.app.AlertDialog; import android.content.Context; +import android.support.v7.app.AlertDialog; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient;