diff --git a/app/shared/src/main/AndroidManifest.xml b/app/shared/src/main/AndroidManifest.xml
index 096449b52..9afc17dfb 100644
--- a/app/shared/src/main/AndroidManifest.xml
+++ b/app/shared/src/main/AndroidManifest.xml
@@ -8,6 +8,7 @@
+
sCache = new HashMap<>();
-
- private PathStrategy mStrategy;
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public void attachInfo(Context context, ProviderInfo info) {
- super.attachInfo(context, info);
-
- if (info.exported) {
- throw new SecurityException("Provider must not be exported");
- }
- if (!info.grantUriPermissions) {
- throw new SecurityException("Provider must grant uri permissions");
- }
-
- mStrategy = getPathStrategy(context, info.authority.split(";")[0]);
- }
-
- public static Uri getUriForFile(Context context, String authority, File file) {
- final PathStrategy strategy = getPathStrategy(context, authority);
- return strategy.getUriForFile(file);
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
- final File file = mStrategy.getFileForUri(uri);
-
- if (projection == null) {
- projection = COLUMNS;
- }
-
- String[] cols = new String[projection.length];
- Object[] values = new Object[projection.length];
- int i = 0;
- for (String col : projection) {
- if (OpenableColumns.DISPLAY_NAME.equals(col)) {
- cols[i] = OpenableColumns.DISPLAY_NAME;
- values[i++] = file.getName();
- } else if (OpenableColumns.SIZE.equals(col)) {
- cols[i] = OpenableColumns.SIZE;
- values[i++] = file.length();
- }
- }
-
- cols = copyOf(cols, i);
- values = copyOf(values, i);
-
- final MatrixCursor cursor = new MatrixCursor(cols, 1);
- cursor.addRow(values);
- return cursor;
- }
-
- @Override
- public String getType(Uri uri) {
- final File file = mStrategy.getFileForUri(uri);
-
- final int lastDot = file.getName().lastIndexOf('.');
- if (lastDot >= 0) {
- final String extension = file.getName().substring(lastDot + 1);
- final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
- if (mime != null) {
- return mime;
- }
- }
-
- return "application/octet-stream";
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- throw new UnsupportedOperationException("No external inserts");
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("No external updates");
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- final File file = mStrategy.getFileForUri(uri);
- return file.delete() ? 1 : 0;
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- final File file = mStrategy.getFileForUri(uri);
- final int fileMode = modeToMode(mode);
- return ParcelFileDescriptor.open(file, fileMode);
- }
-
- private static PathStrategy getPathStrategy(Context context, String authority) {
- PathStrategy strat;
- synchronized (sCache) {
- strat = sCache.get(authority);
- if (strat == null) {
- strat = createPathStrategy(context, authority);
- sCache.put(authority, strat);
- }
- }
- return strat;
- }
-
- private static PathStrategy createPathStrategy(Context context, String authority) {
- final SimplePathStrategy strat = new SimplePathStrategy(authority);
-
- strat.addRoot("root_files", buildPath(DEVICE_ROOT, "."));
- strat.addRoot("internal_files", buildPath(context.getFilesDir(), "."));
- strat.addRoot("cache_files", buildPath(context.getCacheDir(), "."));
- strat.addRoot("external_files", buildPath(Environment.getExternalStorageDirectory(), "."));
-
- File[] externalFilesDirs = context.getExternalFilesDirs(null);
- if (externalFilesDirs.length > 0) {
- strat.addRoot("external_file_files", buildPath(externalFilesDirs[0], "."));
- }
- File[] externalCacheDirs = context.getExternalCacheDirs();
- if (externalCacheDirs.length > 0) {
- strat.addRoot("external_cache_files", buildPath(externalCacheDirs[0], "."));
- }
- File[] externalMediaDirs = context.getExternalMediaDirs();
- if (externalMediaDirs.length > 0) {
- strat.addRoot("external_media_files", buildPath(externalMediaDirs[0], "."));
- }
-
- return strat;
- }
-
- interface PathStrategy {
- Uri getUriForFile(File file);
-
- File getFileForUri(Uri uri);
- }
-
- static class SimplePathStrategy implements PathStrategy {
- private final String mAuthority;
- private final HashMap mRoots = new HashMap<>();
-
- SimplePathStrategy(String authority) {
- mAuthority = authority;
- }
-
- void addRoot(String name, File root) {
- if (TextUtils.isEmpty(name)) {
- throw new IllegalArgumentException("Name must not be empty");
- }
-
- try {
- root = root.getCanonicalFile();
- } catch (IOException e) {
- throw new IllegalArgumentException(
- "Failed to resolve canonical path for " + root, e);
- }
-
- mRoots.put(name, root);
- }
-
- @Override
- public Uri getUriForFile(File file) {
- String path;
- try {
- path = file.getCanonicalPath();
- } catch (IOException e) {
- throw new IllegalArgumentException("Failed to resolve canonical path for " + file);
- }
-
- Map.Entry mostSpecific = null;
- for (Map.Entry root : mRoots.entrySet()) {
- final String rootPath = root.getValue().getPath();
- if (path.startsWith(rootPath) && (mostSpecific == null
- || rootPath.length() > mostSpecific.getValue().getPath().length())) {
- mostSpecific = root;
- }
- }
-
- if (mostSpecific == null) {
- throw new IllegalArgumentException(
- "Failed to find configured root that contains " + path);
- }
-
- final String rootPath = mostSpecific.getValue().getPath();
- if (rootPath.endsWith("/")) {
- path = path.substring(rootPath.length());
- } else {
- path = path.substring(rootPath.length() + 1);
- }
-
- path = Uri.encode(mostSpecific.getKey()) + '/' + Uri.encode(path, "/");
- return new Uri.Builder().scheme("content")
- .authority(mAuthority).encodedPath(path).build();
- }
-
- @Override
- public File getFileForUri(Uri uri) {
- String path = uri.getEncodedPath();
-
- final int splitIndex = path.indexOf('/', 1);
- final String tag = Uri.decode(path.substring(1, splitIndex));
- path = Uri.decode(path.substring(splitIndex + 1));
-
- final File root = mRoots.get(tag);
- if (root == null) {
- throw new IllegalArgumentException("Unable to find configured root for " + uri);
- }
-
- File file = new File(root, path);
- try {
- file = file.getCanonicalFile();
- } catch (IOException e) {
- throw new IllegalArgumentException("Failed to resolve canonical path for " + file);
- }
-
- if (!file.getPath().startsWith(root.getPath())) {
- throw new SecurityException("Resolved path jumped beyond configured root");
- }
-
- return file;
- }
- }
-
- private static int modeToMode(String mode) {
- int modeBits;
- if ("r".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
- } else if ("w".equals(mode) || "wt".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
- | ParcelFileDescriptor.MODE_CREATE
- | ParcelFileDescriptor.MODE_TRUNCATE;
- } else if ("wa".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
- | ParcelFileDescriptor.MODE_CREATE
- | ParcelFileDescriptor.MODE_APPEND;
- } else if ("rw".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_WRITE
- | ParcelFileDescriptor.MODE_CREATE;
- } else if ("rwt".equals(mode)) {
- modeBits = ParcelFileDescriptor.MODE_READ_WRITE
- | ParcelFileDescriptor.MODE_CREATE
- | ParcelFileDescriptor.MODE_TRUNCATE;
- } else {
- throw new IllegalArgumentException("Invalid mode: " + mode);
- }
- return modeBits;
- }
-
- private static File buildPath(File base, String... segments) {
- File cur = base;
- for (String segment : segments) {
- if (segment != null) {
- cur = new File(cur, segment);
- }
- }
- return cur;
- }
-
- private static String[] copyOf(String[] original, int newLength) {
- final String[] result = new String[newLength];
- System.arraycopy(original, 0, result, 0, newLength);
- return result;
- }
-
- private static Object[] copyOf(Object[] original, int newLength) {
- final Object[] result = new Object[newLength];
- System.arraycopy(original, 0, result, 0, newLength);
- return result;
- }
-}
diff --git a/app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java b/app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
index d76b3a7e8..418bd5756 100644
--- a/app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
+++ b/app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
@@ -1,51 +1,121 @@
package com.topjohnwu.magisk.utils;
-import android.app.Activity;
+import static android.content.pm.PackageInstaller.EXTRA_STATUS;
+import static android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID;
+import static android.content.pm.PackageInstaller.STATUS_PENDING_USER_ACTION;
+import static android.content.pm.PackageInstaller.STATUS_SUCCESS;
+
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInstaller.Session;
+import android.content.pm.PackageInstaller.SessionParams;
import android.net.Uri;
import android.os.Build;
-
-import com.topjohnwu.magisk.FileProvider;
+import android.util.Log;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import io.michaelrocks.paranoid.Obfuscate;
@Obfuscate
-public class APKInstall {
+public final class APKInstall {
+ // @WorkerThread
+ public static void installapk(Context context, File apk) {
+ //noinspection InlinedApi
+ var flag = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE;
+ var action = APKInstall.class.getName();
+ var intent = new Intent(action).setPackage(context.getPackageName());
+ var pending = PendingIntent.getBroadcast(context, 0, intent, flag);
- public static Intent installIntent(Context c, File apk) {
- Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
- intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (Build.VERSION.SDK_INT >= 24) {
- intent.setData(FileProvider.getUriForFile(c, c.getPackageName() + ".provider", apk));
- } else {
- //noinspection ResultOfMethodCallIgnored SetWorldReadable
- apk.setReadable(true, false);
- intent.setData(Uri.fromFile(apk));
+ var installer = context.getPackageManager().getPackageInstaller();
+ var params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ params.setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED);
+ }
+ try (Session session = installer.openSession(installer.createSession(params))) {
+ OutputStream out = session.openWrite(apk.getName(), 0, apk.length());
+ try (var in = new FileInputStream(apk); out) {
+ transfer(in, out);
+ }
+ session.commit(pending.getIntentSender());
+ } catch (IOException e) {
+ Log.e(APKInstall.class.getSimpleName(), "", e);
}
- return intent;
}
- public static void install(Context c, File apk) {
- c.startActivity(installIntent(c, apk));
+ public static void transfer(InputStream in, OutputStream out) throws IOException {
+ int size = 8192;
+ var buffer = new byte[size];
+ int read;
+ while ((read = in.read(buffer, 0, size)) >= 0) {
+ out.write(buffer, 0, read);
+ }
}
- public static void registerInstallReceiver(Context c, BroadcastReceiver r) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ public static InstallReceiver register(Context context, String packageName, Runnable onSuccess) {
+ var receiver = new InstallReceiver(context, packageName, onSuccess);
+ var filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
- c.getApplicationContext().registerReceiver(r, filter);
+ context.registerReceiver(receiver, filter);
+ context.registerReceiver(receiver, new IntentFilter(APKInstall.class.getName()));
+ return receiver;
}
- public static void installHideResult(Activity c, File apk) {
- Intent intent = installIntent(c, apk);
- intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
- c.startActivityForResult(intent, 0); // Ignore result, use install receiver
+ public static class InstallReceiver extends BroadcastReceiver {
+ private final Context context;
+ private final String packageName;
+ private final Runnable onSuccess;
+ private final CountDownLatch latch = new CountDownLatch(1);
+ private Intent intent = null;
+
+ private InstallReceiver(Context context, String packageName, Runnable onSuccess) {
+ this.context = context;
+ this.packageName = packageName;
+ this.onSuccess = onSuccess;
+ }
+
+ @Override
+ public void onReceive(Context c, Intent i) {
+ if (Intent.ACTION_PACKAGE_ADDED.equals(i.getAction())) {
+ Uri data = i.getData();
+ if (data == null || onSuccess == null) return;
+ String pkg = data.getSchemeSpecificPart();
+ if (pkg.equals(packageName)) {
+ onSuccess.run();
+ context.unregisterReceiver(this);
+ }
+ return;
+ }
+ int status = i.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID);
+ switch (status) {
+ case STATUS_PENDING_USER_ACTION:
+ intent = i.getParcelableExtra(Intent.EXTRA_INTENT);
+ break;
+ case STATUS_SUCCESS:
+ if (onSuccess != null) onSuccess.run();
+ default:
+ context.unregisterReceiver(this);
+ }
+ latch.countDown();
+ }
+
+ // @WorkerThread @Nullable
+ public Intent waitIntent() {
+ try {
+ //noinspection ResultOfMethodCallIgnored
+ latch.await(5, TimeUnit.SECONDS);
+ } catch (Exception ignored) {
+ }
+ return intent;
+ }
}
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/Provider.kt b/app/src/main/java/com/topjohnwu/magisk/core/Provider.kt
index b5ac6ef95..6acc662af 100644
--- a/app/src/main/java/com/topjohnwu/magisk/core/Provider.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/core/Provider.kt
@@ -1,18 +1,20 @@
package com.topjohnwu.magisk.core
+import android.content.ContentProvider
+import android.content.ContentValues
import android.content.Context
import android.content.pm.ProviderInfo
+import android.database.Cursor
import android.net.Uri
import android.os.Bundle
import android.os.ParcelFileDescriptor
import android.os.ParcelFileDescriptor.MODE_READ_ONLY
-import com.topjohnwu.magisk.FileProvider
import com.topjohnwu.magisk.core.su.SuCallbackHandler
import java.io.File
-open class Provider : FileProvider() {
+class Provider : ContentProvider() {
- override fun attachInfo(context: Context, info: ProviderInfo?) {
+ override fun attachInfo(context: Context, info: ProviderInfo) {
super.attachInfo(context.wrap(), info)
}
@@ -36,4 +38,11 @@ open class Provider : FileProvider() {
fun PREFS_URI(pkg: String) =
Uri.Builder().scheme("content").authority("$pkg.provider").path("prefs_file").build()
}
+
+ override fun onCreate() = true
+ override fun getType(uri: Uri): String? = null
+ override fun insert(uri: Uri, values: ContentValues?): Uri? = null
+ override fun delete(uri: Uri, selection: String?, selectionArgs: Array?) = 0
+ override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array?) = 0
+ override fun query(uri: Uri, projection: Array?, selection: String?, selectionArgs: Array?, sortOrder: String?): Cursor? = null
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
index f635e805b..d9ada0970 100644
--- a/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
@@ -73,8 +73,12 @@ sealed class Subject : Parcelable {
val externalFile get() = MediaStoreUtils.getFile("$title.apk").uri
- override fun pendingIntent(context: Context) =
- APKInstall.installIntent(context, file.toFile()).toPending(context)
+ override fun pendingIntent(context: Context): PendingIntent {
+ val receiver = APKInstall.register(context, null, null)
+ APKInstall.installapk(context, file.toFile())
+ val intent = receiver.waitIntent() ?: Intent()
+ return intent.toPending(context)
+ }
}
@SuppressLint("InlinedApi")
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt b/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
index a5bdff0bc..43ede587e 100644
--- a/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
@@ -1,7 +1,6 @@
package com.topjohnwu.magisk.core.tasks
import android.app.Activity
-import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast
@@ -27,7 +26,6 @@ import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
-import java.lang.ref.WeakReference
import java.security.SecureRandom
object HideAPK {
@@ -41,8 +39,6 @@ object HideAPK {
const val MAX_LABEL_LENGTH = 32
private val svc get() = ServiceLocator.networkService
- private val Context.APK_URI get() = Provider.APK_URI(packageName)
- private val Context.PREFS_URI get() = Provider.PREFS_URI(packageName)
private fun genPackageName(): String {
val random = SecureRandom()
@@ -92,35 +88,16 @@ object HideAPK {
return true
}
- private class WaitPackageReceiver(
- private val pkg: String,
- activity: Activity
- ) : BroadcastReceiver() {
-
- private val activity = WeakReference(activity)
-
- private fun launchApp(): Unit = activity.get()?.run {
- val intent = packageManager.getLaunchIntentForPackage(pkg) ?: return
- Config.suManager = if (pkg == APPLICATION_ID) "" else pkg
- grantUriPermission(pkg, APK_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
- grantUriPermission(pkg, PREFS_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
- intent.putExtra(Const.Key.PREV_PKG, packageName)
- startActivity(intent)
- finish()
- } ?: Unit
-
- override fun onReceive(context: Context, intent: Intent) {
- when (intent.action ?: return) {
- Intent.ACTION_PACKAGE_REPLACED, Intent.ACTION_PACKAGE_ADDED -> {
- val newPkg = intent.data?.encodedSchemeSpecificPart.orEmpty()
- if (newPkg == pkg) {
- context.unregisterReceiver(this)
- launchApp()
- }
- }
- }
- }
-
+ private fun launchApp(activity: Activity, pkg: String) {
+ val intent = activity.packageManager.getLaunchIntentForPackage(pkg) ?: return
+ Config.suManager = if (pkg == APPLICATION_ID) "" else pkg
+ val self = activity.packageName
+ val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
+ activity.grantUriPermission(pkg, Provider.APK_URI(self), flag)
+ activity.grantUriPermission(pkg, Provider.PREFS_URI(self), flag)
+ intent.putExtra(Const.Key.PREV_PKG, self)
+ activity.startActivity(intent)
+ activity.finish()
}
private suspend fun patchAndHide(activity: Activity, label: String): Boolean {
@@ -141,9 +118,14 @@ object HideAPK {
return false
// Install and auto launch app
- APKInstall.registerInstallReceiver(activity, WaitPackageReceiver(pkg, activity))
- if (!Shell.su("adb_pm_install $repack").exec().isSuccess)
- APKInstall.installHideResult(activity, repack)
+ val receiver = APKInstall.register(activity, pkg) {
+ launchApp(activity, pkg)
+ }
+ val cmd = "adb_pm_install $repack ${activity.applicationInfo.uid}"
+ if (!Shell.su(cmd).exec().isSuccess) {
+ APKInstall.installapk(activity, repack)
+ receiver.waitIntent()?.let { activity.startActivity(it) }
+ }
return true
}
@@ -157,8 +139,8 @@ object HideAPK {
val result = withContext(Dispatchers.IO) {
patchAndHide(activity, label)
}
- dialog.dismiss()
if (!result) {
+ dialog.dismiss()
Utils.toast(R.string.failure, Toast.LENGTH_LONG)
}
}
@@ -171,11 +153,15 @@ object HideAPK {
show()
}
val apk = DynAPK.current(activity)
- APKInstall.registerInstallReceiver(activity, WaitPackageReceiver(APPLICATION_ID, activity))
- Shell.su("adb_pm_install $apk").submit {
+ val receiver = APKInstall.register(activity, APPLICATION_ID) {
+ launchApp(activity, APPLICATION_ID)
dialog.dismiss()
- if (!it.isSuccess)
- APKInstall.installHideResult(activity, apk)
+ }
+ val cmd = "adb_pm_install $apk ${activity.applicationInfo.uid}"
+ Shell.su(cmd).submit(Shell.EXECUTOR) { ret ->
+ if (ret.isSuccess) return@submit
+ APKInstall.installapk(activity, apk)
+ receiver.waitIntent()?.let { activity.startActivity(it) }
}
}
}
diff --git a/app/src/main/res/raw/manager.sh b/app/src/main/res/raw/manager.sh
index 966859752..87c56d2e7 100644
--- a/app/src/main/res/raw/manager.sh
+++ b/app/src/main/res/raw/manager.sh
@@ -129,9 +129,11 @@ adb_pm_install() {
local tmp=/data/local/tmp/temp.apk
cp -f "$1" $tmp
chmod 644 $tmp
- su 2000 -c pm install $tmp || pm install $tmp
+ su 2000 -c pm install $tmp || pm install $tmp || su 1000 -c pm install $tmp
local res=$?
rm -f $tmp
+ # Note: change this will kill self
+ [ $res != 0 ] && appops set "$2" REQUEST_INSTALL_PACKAGES allow
return $res
}
diff --git a/buildSrc/src/main/java/Codegen.kt b/buildSrc/src/main/java/Codegen.kt
index 0125aad32..6e5a4bd12 100644
--- a/buildSrc/src/main/java/Codegen.kt
+++ b/buildSrc/src/main/java/Codegen.kt
@@ -105,7 +105,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
cmpList.add(Component(
"com.topjohnwu.magisk.core.Provider",
- "FileProvider",
+ "dummy.DummyProvider",
"""
|(); }
-keepclassmembers class com.topjohnwu.magisk.DownloadActivity { (); }
--keepclassmembers class com.topjohnwu.magisk.FileProvider { (); }
-keepclassmembers class com.topjohnwu.magisk.DelegateRootService { (); }
diff --git a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java
index fa2810f80..e2ff4e5e1 100644
--- a/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java
+++ b/stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java
@@ -12,6 +12,7 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
+import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
@@ -79,6 +80,7 @@ public class DownloadActivity extends Activity {
private void error(Throwable e) {
Log.e(getClass().getSimpleName(), "", e);
+ Toast.makeText(themed, e.getMessage(), Toast.LENGTH_LONG).show();
finish();
}
@@ -111,22 +113,22 @@ public class DownloadActivity extends Activity {
private void dlAPK() {
dialog = ProgressDialog.show(themed, getString(dling), getString(dling) + " " + APP_NAME, true);
+ Runnable onSuccess = () -> {
+ dialog.dismiss();
+ Toast.makeText(themed, relaunch_app, Toast.LENGTH_LONG).show();
+ finish();
+ };
// Download and upgrade the app
File apk = dynLoad ? DynAPK.current(this) : new File(getCacheDir(), "manager.apk");
request(apkLink).setExecutor(AsyncTask.THREAD_POOL_EXECUTOR).getAsFile(apk, file -> {
if (dynLoad) {
DynLoad.setup(this);
- runOnUiThread(() -> {
- dialog.dismiss();
- Toast.makeText(themed, relaunch_app, Toast.LENGTH_LONG).show();
- finish();
- });
+ onSuccess.run();
} else {
- runOnUiThread(() -> {
- dialog.dismiss();
- APKInstall.install(this, file);
- finish();
- });
+ var receiver = APKInstall.register(this, BuildConfig.APPLICATION_ID, onSuccess);
+ APKInstall.installapk(this, file);
+ Intent intent = receiver.waitIntent();
+ if (intent != null) startActivity(intent);
}
});
}
@@ -141,15 +143,10 @@ public class DownloadActivity extends Activity {
InputStream is = new CipherInputStream(new ByteArrayInputStream(Bytes.res()), cipher);
try (InputStream gzip = new GZIPInputStream(is);
OutputStream out = new FileOutputStream(apk)) {
- byte[] buf = new byte[4096];
- for (int read; (read = gzip.read(buf)) >= 0;) {
- out.write(buf, 0, read);
- }
+ APKInstall.transfer(gzip, out);
}
DynAPK.addAssetPath(getResources().getAssets(), apk.getPath());
- } catch (Exception e) {
- // Should not happen
- e.printStackTrace();
+ } catch (Exception ignored) {
}
}