1
mirror of https://github.com/topjohnwu/Magisk synced 2025-10-26 02:22:14 +01:00

Compare commits

...

32 Commits

Author SHA1 Message Date
Dmitry Val'd
13bf1b27b4 Update strings.xml
Added new lines from original
2017-10-15 03:15:39 +08:00
topjohnwu
f742bb1c47 Hot fix for detecting MagiskHide 2017-10-15 03:12:13 +08:00
topjohnwu
aa0b9e2db2 Bump version 2017-10-14 04:18:14 +08:00
topjohnwu
c10076f7ed Remove debug logs 2017-10-14 04:05:41 +08:00
topjohnwu
bcd92499f2 Massive improvement on Online Repo fetching 2017-10-14 04:05:41 +08:00
topjohnwu
b2bb0d4f72 Fix some external storage permission issues 2017-10-14 00:36:10 +08:00
topjohnwu
e140481f14 Wrap wrapper with buffer 2017-10-13 20:47:14 +08:00
topjohnwu
186bd11463 Reconnect until we got content length 2017-10-13 03:25:56 +08:00
topjohnwu
a0490d6687 Update Trad. Chinese translation 2017-10-13 03:10:35 +08:00
killer7mod
beef740ade update strings.xml for PT-BR 2017-10-13 02:45:02 +08:00
Frieder Bluemle
2ac7786a90 Update commonmark to 0.10.0 2017-10-13 02:44:42 +08:00
Frieder Bluemle
a3fb5e910f Update bouncycastle libs to 1.58 2017-10-13 02:44:42 +08:00
Frieder Bluemle
319afe86b5 Update Gradle wrapper to 4.2.1 2017-10-13 02:44:42 +08:00
Frieder Bluemle
762ab66b86 Fix Lint errors 2017-10-13 02:44:42 +08:00
topjohnwu
0c239a42de Allow secondary users to control Superuser settings except multiuser options 2017-10-13 02:41:43 +08:00
dark-basic #DarkBasic BasicHD
e9322fba26 Update strings.xml
New Lines Added
2017-10-07 23:44:10 +08:00
RoySchutte
39b6df27b3 Update strings.xml 2017-10-07 20:55:00 +08:00
topjohnwu
b1ee284e7f Rename resource -> common 2017-10-07 20:48:45 +08:00
topjohnwu
e986332bf2 Several small snet fixes 2017-10-07 20:47:44 +08:00
topjohnwu
48f9b27381 Seperate JarSigner and add task for host 2017-10-07 20:31:49 +08:00
topjohnwu
42a6e0dd10 Seperate Google proprietary code 2017-10-07 17:12:36 +08:00
topjohnwu
d4798b02ac Move functions 2017-10-04 22:27:14 +08:00
topjohnwu
963edfe8ab Add InputStream mode for signing zips 2017-10-04 22:09:59 +08:00
topjohnwu
53237f3ae0 Update Android Studio and Proguard configs 2017-10-04 15:23:08 +08:00
topjohnwu
64da9281a4 Show progress while downloading modules 2017-10-01 02:38:25 +08:00
topjohnwu
ab7fd9799d Remove cache module exception 2017-10-01 01:38:25 +08:00
topjohnwu
f6bcc84251 Improve repo fetching 2017-10-01 01:28:50 +08:00
topjohnwu
35dc3d9df9 Update WebService 2017-10-01 01:12:45 +08:00
topjohnwu
566714a75d Use override functions 2017-09-30 03:25:50 +08:00
topjohnwu
c92f30b122 Re-organize classes 2017-09-30 03:04:23 +08:00
topjohnwu
294ad094c4 Show repo loading progress by showing repos already loaded 2017-09-30 01:15:34 +08:00
topjohnwu
c1a0f520f9 Prevent flash screen close when tapping outside 2017-09-29 13:20:34 +08:00
97 changed files with 1744 additions and 1316 deletions

View File

@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
buildToolsVersion "26.0.2"
defaultConfig {
applicationId "com.topjohnwu.magisk"
minSdkVersion 21
targetSdkVersion 26
versionCode 55
versionName "5.3.5"
versionCode 57
versionName "5.4.0"
ndk {
moduleName 'zipadjust'
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
@@ -53,16 +53,14 @@ repositories {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':resource')
implementation project(':common')
implementation project(':jarsigner')
implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.android.support:cardview-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.jakewharton:butterknife:8.8.1'
implementation 'com.atlassian.commonmark:commonmark:0.9.0'
implementation 'org.bouncycastle:bcprov-jdk15on:1.57'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.57'
implementation 'com.atlassian.commonmark:commonmark:0.10.0'
implementation 'org.kamranzafar:jtar:2.3'
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

View File

@@ -16,10 +16,9 @@
# public *;
#}
# Keep all names, we are open source anyway :)
-keepnames class ** { *; }
# BouncyCastle
-keep class org.bouncycastle.** { *; }
-keep class org.bouncycastle.jcajce.provider.** { *; }
-dontwarn javax.naming.**
-dontwarn android.content.**
-dontwarn android.animation.**

View File

@@ -90,9 +90,10 @@
android:resource="@xml/file_paths" />
</provider>
<!-- Hardcode GMS version -->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
android:value="11400000" />
</application>

View File

@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.components.AlertDialogBuilder;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -57,7 +58,7 @@ public class AboutActivity extends Activity {
ab.setDisplayHomeAsUpEnabled(true);
}
appVersionInfo.setSummary(BuildConfig.VERSION_NAME);
appVersionInfo.setSummary(String.format(Locale.US, "%s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
String changes = null;
try (InputStream is = getAssets().open("changelog.html")) {

View File

@@ -16,7 +16,7 @@ import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.FlashZip;
import com.topjohnwu.magisk.asyncs.InstallMagisk;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.utils.AdaptiveList;
import com.topjohnwu.magisk.container.AdaptiveList;
import com.topjohnwu.magisk.utils.Shell;
import java.util.List;
@@ -63,6 +63,7 @@ public class FlashActivity extends Activity {
ab.setTitle(R.string.flashing);
}
setFloating();
setFinishOnTouchOutside(false);
if (!Shell.rootAccess())
reboot.setVisibility(View.GONE);
@@ -148,4 +149,5 @@ public class FlashActivity extends Activity {
ButterKnife.bind(this, itemView);
}
}
}

View File

@@ -4,6 +4,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.CardView;
@@ -19,7 +20,9 @@ import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;
import com.topjohnwu.magisk.asyncs.CheckSafetyNet;
import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.components.SnackbarMaker;
@@ -39,6 +42,13 @@ import butterknife.Unbinder;
public class MagiskFragment extends Fragment
implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView {
public static final int CAUSE_SERVICE_DISCONNECTED = 0x00001;
public static final int CAUSE_NETWORK_LOST = 0x00010;
public static final int RESPONSE_ERR = 0x00100;
public static final int BASIC_PASS = 0x01000;
public static final int CTS_PASS = 0x10000;
private Container expandableContainer = new Container();
private MagiskManager mm;
@@ -85,11 +95,26 @@ public class MagiskFragment extends Fragment
@OnClick(R.id.safetyNet_title)
void safetyNet() {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetRefreshIcon.setVisibility(View.GONE);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
Utils.checkSafetyNet(getActivity());
collapse();
Runnable task = () -> {
safetyNetProgress.setVisibility(View.VISIBLE);
safetyNetRefreshIcon.setVisibility(View.GONE);
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
new CheckSafetyNet(getActivity()).exec();
collapse();
};
if (mm.snet_version < 0) {
// Show dialog
new AlertDialogBuilder(getActivity())
.setTitle(R.string.proprietary_title)
.setMessage(R.string.proprietary_notice)
.setCancelable(true)
.setPositiveButton(R.string.yes, (d, i) -> task.run())
.setNegativeButton(R.string.no_thanks, null)
.show();
} else {
task.run();
}
}
@OnClick(R.id.install_button)
@@ -158,11 +183,11 @@ public class MagiskFragment extends Fragment
}
@Override
public void onTopicPublished(Topic topic) {
public void onTopicPublished(Topic topic, Object result) {
if (topic == mm.updateCheckDone) {
updateCheckUI();
} else if (topic == mm.safetyNetDone) {
updateSafetyNetUI();
updateSafetyNetUI((int) result);
}
}
@@ -302,37 +327,41 @@ public class MagiskFragment extends Fragment
mSwipeRefreshLayout.setRefreshing(false);
}
private void updateSafetyNetUI() {
int image, color;
private void updateSafetyNetUI(int response) {
safetyNetProgress.setVisibility(View.GONE);
safetyNetRefreshIcon.setVisibility(View.VISIBLE);
if (mm.SNCheckResult.failed) {
safetyNetStatusText.setText(mm.SNCheckResult.errmsg);
collapse();
} else {
if (response < 0) {
safetyNetStatusText.setText(R.string.safetyNet_api_error);
} else if ((response & 0x111) == 0) {
safetyNetStatusText.setText(R.string.safetyNet_check_success);
if (mm.SNCheckResult.ctsProfile) {
color = colorOK;
image = R.drawable.ic_check_circle;
} else {
color = colorBad;
image = R.drawable.ic_cancel;
}
ctsStatusText.setText("ctsProfile: " + mm.SNCheckResult.ctsProfile);
ctsStatusIcon.setImageResource(image);
ctsStatusIcon.setColorFilter(color);
if (mm.SNCheckResult.basicIntegrity) {
color = colorOK;
image = R.drawable.ic_check_circle;
} else {
color = colorBad;
image = R.drawable.ic_cancel;
}
basicStatusText.setText("basicIntegrity: " + mm.SNCheckResult.basicIntegrity);
basicStatusIcon.setImageResource(image);
basicStatusIcon.setColorFilter(color);
boolean b;
b = (response & CTS_PASS) != 0;
ctsStatusText.setText("ctsProfile: " + b);
ctsStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
ctsStatusIcon.setColorFilter(b ? colorOK : colorBad);
b = (response & BASIC_PASS) != 0;
basicStatusText.setText("basicIntegrity: " + b);
basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
basicStatusIcon.setColorFilter(b ? colorOK : colorBad);
expand();
} else {
@StringRes int resid;
switch (response) {
case CAUSE_SERVICE_DISCONNECTED:
resid = R.string.safetyNet_network_loss;
break;
case CAUSE_NETWORK_LOST:
resid = R.string.safetyNet_service_disconnected;
break;
case RESPONSE_ERR:
default:
resid = R.string.safetyNet_res_invalid;
break;
}
safetyNetStatusText.setText(resid);
}
}
}

View File

@@ -84,7 +84,7 @@ public class MagiskHideFragment extends Fragment implements Topic.Subscriber {
}
@Override
public void onTopicPublished(Topic topic) {
public void onTopicPublished(Topic topic, Object result) {
mSwipeRefreshLayout.setRefreshing(false);
appAdapter.filter(lastFilter);
}

View File

@@ -20,13 +20,12 @@ import com.topjohnwu.magisk.asyncs.DownloadBusybox;
import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.asyncs.ParallelTask;
import com.topjohnwu.magisk.asyncs.UpdateRepos;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.services.UpdateCheckService;
import com.topjohnwu.magisk.superuser.SuReceiver;
import com.topjohnwu.magisk.superuser.SuRequestActivity;
import com.topjohnwu.magisk.utils.SafetyNetHelper;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
@@ -72,7 +71,6 @@ public class MagiskManager extends Application {
public String remoteManagerVersionString;
public int remoteManagerVersionCode = -1;
public String managerLink;
public SafetyNetHelper.Result SNCheckResult;
public String bootBlock = null;
public boolean isSuClient = false;
public String suVersion = null;
@@ -84,8 +82,6 @@ public class MagiskManager extends Application {
public List<Locale> locales;
// Configurations
public static boolean shellLogging;
public static boolean devLogging;
public static Locale locale;
public static Locale defaultLocale;
@@ -103,6 +99,7 @@ public class MagiskManager extends Application {
public String localeConfig;
public int updateChannel;
public String bootFormat;
public int snet_version;
// Global resources
public SharedPreferences prefs;
@@ -164,13 +161,6 @@ public class MagiskManager extends Application {
public void loadConfig() {
isDarkTheme = prefs.getBoolean("dark_theme", false);
if (BuildConfig.DEBUG) {
devLogging = prefs.getBoolean("developer_logging", false);
shellLogging = prefs.getBoolean("shell_logging", false);
} else {
devLogging = false;
shellLogging = false;
}
// su
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
@@ -184,6 +174,7 @@ public class MagiskManager extends Application {
updateNotification = prefs.getBoolean("notification", true);
updateChannel = Utils.getPrefsInt(prefs, "update_channel", CheckUpdates.STABLE_CHANNEL);
bootFormat = prefs.getString("boot_format", ".img");
snet_version = prefs.getInt("snet_version", -1);
}
public void toast(String msg, int duration) {
@@ -284,7 +275,7 @@ public class MagiskManager extends Application {
.setPeriodic(8 * 60 * 60 * 1000)
.build();
((JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo);
loadModuleTask.setCallBack(() -> new UpdateRepos(this).exec());
loadModuleTask.setCallBack(() -> new UpdateRepos(this, false).exec());
}
// Fire asynctasks
loadModuleTask.exec();
@@ -321,7 +312,11 @@ public class MagiskManager extends Application {
} catch (NumberFormatException e) {
disabled = false;
}
ret = shell.sh("getprop " + MAGISKHIDE_PROP);
if (magiskVersionCode > 1435) {
ret = shell.su("resetprop -p " + MAGISKHIDE_PROP);
} else {
ret = shell.sh("getprop " + MAGISKHIDE_PROP);
}
try {
magiskHide = !Utils.isValidShellResponse(ret) || Integer.parseInt(ret.get(0)) != 0;
} catch (NumberFormatException e) {

View File

@@ -102,7 +102,7 @@ public class MainActivity extends Activity
}
@Override
public void onTopicPublished(Topic topic) {
public void onTopicPublished(Topic topic, Object result) {
recreate();
}

View File

@@ -1,5 +1,6 @@
package com.topjohnwu.magisk;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
@@ -14,9 +15,9 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.ModulesAdapter;
import com.topjohnwu.magisk.asyncs.LoadModules;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
import java.util.ArrayList;
import java.util.List;
@@ -36,9 +37,11 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
@BindView(R.id.empty_rv) TextView emptyRv;
@OnClick(R.id.fab)
public void selectFile() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("application/zip");
startActivityForResult(intent, FETCH_ZIP_CODE);
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, () -> {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("application/zip");
startActivityForResult(intent, FETCH_ZIP_CODE);
});
}
private List<Module> listModules = new ArrayList<>();
@@ -72,8 +75,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
}
@Override
public void onTopicPublished(Topic topic) {
Logger.dev("ModulesFragment: UI refresh triggered");
public void onTopicPublished(Topic topic, Object result) {
updateUI();
}

View File

@@ -15,7 +15,6 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.ReposAdapter;
import com.topjohnwu.magisk.asyncs.UpdateRepos;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Topic;
import butterknife.BindView;
@@ -29,7 +28,7 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
@BindView(R.id.empty_rv) TextView emptyRv;
@BindView(R.id.swipeRefreshLayout) SwipeRefreshLayout mSwipeRefreshLayout;
private ReposAdapter adapter;
public static ReposAdapter adapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -43,14 +42,12 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
View view = inflater.inflate(R.layout.fragment_repos, container, false);
unbinder = ButterKnife.bind(this, view);
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
recyclerView.setAdapter(adapter);
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.setOnRefreshListener(() -> {
recyclerView.setVisibility(View.GONE);
new UpdateRepos(getActivity()).exec();
recyclerView.setVisibility(View.VISIBLE);
emptyRv.setVisibility(View.GONE);
new UpdateRepos(getActivity(), true).exec();
});
getActivity().setTitle(R.string.downloads);
@@ -59,10 +56,21 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
}
@Override
public void onTopicPublished(Topic topic) {
Logger.dev("ReposFragment: UI refresh triggered");
public void onResume() {
adapter = new ReposAdapter(getApplication().repoDB, getApplication().moduleMap);
recyclerView.setAdapter(adapter);
super.onResume();
}
@Override
public void onPause() {
super.onPause();
adapter = null;
}
@Override
public void onTopicPublished(Topic topic, Object result) {
mSwipeRefreshLayout.setRefreshing(false);
adapter.notifyDBChanged();
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
}

View File

@@ -19,7 +19,6 @@ import com.topjohnwu.magisk.asyncs.CheckUpdates;
import com.topjohnwu.magisk.asyncs.HideManager;
import com.topjohnwu.magisk.components.Activity;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Topic;
import com.topjohnwu.magisk.utils.Utils;
@@ -62,7 +61,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
}
@Override
public void onTopicPublished(Topic topic) {
public void onTopicPublished(Topic topic, Object result) {
recreate();
}
@@ -94,7 +93,6 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
generalCatagory = (PreferenceCategory) findPreference("general");
PreferenceCategory magiskCategory = (PreferenceCategory) findPreference("magisk");
PreferenceCategory suCategory = (PreferenceCategory) findPreference("superuser");
PreferenceCategory developer = (PreferenceCategory) findPreference("developer");
updateChannel = (ListPreference) findPreference("update_channel");
suAccess = (ListPreference) findPreference("su_access");
@@ -110,8 +108,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
// Disable dangerous settings in user mode if selected owner manage
if (getActivity().getApplicationInfo().uid > 99999) {
prefScreen.removePreference(magiskCategory);
prefScreen.removePreference(suCategory);
suCategory.removePreference(multiuserMode);
generalCatagory.removePreference(hideManager);
}
@@ -132,10 +129,6 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
return true;
});
if (!BuildConfig.DEBUG) {
prefScreen.removePreference(developer);
}
if (!Shell.rootAccess()) {
prefScreen.removePreference(magiskCategory);
prefScreen.removePreference(suCategory);
@@ -190,7 +183,6 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Logger.dev("Settings: Prefs change " + key);
boolean enabled;
switch (key) {
@@ -273,7 +265,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
}
@Override
public void onTopicPublished(Topic topic) {
public void onTopicPublished(Topic topic, Object result) {
setLocalePreference((ListPreference) findPreference("locale"));
}

View File

@@ -11,7 +11,7 @@ import android.widget.TextView;
import com.topjohnwu.magisk.adapters.PolicyAdapter;
import com.topjohnwu.magisk.components.Fragment;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.container.Policy;
import java.util.List;

View File

@@ -13,7 +13,7 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.utils.Shell;
import java.util.List;

View File

@@ -15,8 +15,8 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.components.SnackbarMaker;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.Policy;
import java.util.HashSet;
import java.util.List;

View File

@@ -17,9 +17,9 @@ import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
import com.topjohnwu.magisk.components.AlertDialogBuilder;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.container.Repo;
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.module.Repo;
import com.topjohnwu.magisk.utils.Utils;
import java.util.ArrayList;
@@ -44,6 +44,7 @@ public class ReposAdapter extends SectionedAdapter<ReposAdapter.SectionHolder, R
repoDB = db;
moduleMap = map;
repoPairs = new ArrayList<>();
notifyDBChanged();
}

View File

@@ -12,8 +12,8 @@ import android.widget.TextView;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.components.ExpandableView;
import com.topjohnwu.magisk.container.SuLogEntry;
import com.topjohnwu.magisk.database.SuDatabaseHelper;
import com.topjohnwu.magisk.superuser.SuLogEntry;
import java.util.Collections;
import java.util.HashSet;

View File

@@ -0,0 +1,84 @@
package com.topjohnwu.magisk.asyncs;
import android.support.v4.app.FragmentActivity;
import com.topjohnwu.jarsigner.ByteArrayStream;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.WebService;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import dalvik.system.DexClassLoader;
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
public static final int SNET_VER = 2;
private static final String SNET_URL = "https://github.com/topjohnwu/MagiskManager/releases/download/v5.4.0/snet.apk";
private static final String PKG = "com.topjohnwu.snet";
private File dexPath;
private DexClassLoader loader;
public CheckSafetyNet(FragmentActivity activity) {
super(activity);
dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk");
}
@Override
protected void onPreExecute() {
MagiskManager mm = getMagiskManager();
if (mm.snet_version != CheckSafetyNet.SNET_VER) {
getShell().sh("rm -rf " + dexPath.getParent());
}
mm.snet_version = CheckSafetyNet.SNET_VER;
mm.prefs.edit().putInt("snet_version", CheckSafetyNet.SNET_VER).apply();
}
@Override
protected Exception doInBackground(Void... voids) {
try {
if (!dexPath.exists()) {
HttpURLConnection conn = WebService.request(SNET_URL, null);
ByteArrayStream bas = new ByteArrayStream();
bas.readFrom(conn.getInputStream());
conn.disconnect();
dexPath.getParentFile().mkdir();
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath))) {
bas.writeTo(out);
out.flush();
}
}
loader = new DexClassLoader(dexPath.toString(), dexPath.getParent(),
null, ClassLoader.getSystemClassLoader());
} catch (Exception e) {
return e;
}
return null;
}
@Override
protected void onPostExecute(Exception err) {
try {
if (err != null) throw err;
Class<?> helperClazz = loader.loadClass(PKG + ".SafetyNetHelper");
Class<?> callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback");
Object helper = helperClazz.getConstructors()[0].newInstance(
getActivity(), Proxy.newProxyInstance(
loader, new Class[] { callbackClazz }, (proxy, method, args) -> {
getMagiskManager().safetyNetDone.publish(false, args[0]);
return null;
}));
helperClazz.getMethod("attest").invoke(helper);
} catch (Exception e) {
e.printStackTrace();
getMagiskManager().safetyNetDone.publish(false, -1);
}
super.onPostExecute(err);
}
}

View File

@@ -11,7 +11,7 @@ import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
@@ -31,22 +31,21 @@ public class DownloadBusybox extends ParallelTask<Void, Void, Void> {
Utils.removeItem(getShell(), context.getApplicationInfo().dataDir + "/busybox");
try {
FileOutputStream out = new FileOutputStream(busybox);
InputStream in = WebService.request(WebService.GET,
HttpURLConnection conn = WebService.request(
Build.SUPPORTED_32_BIT_ABIS[0].contains("x86") ?
BUSYBOX_X86 :
BUSYBOX_ARM,
null
);
if (in == null) throw new IOException();
BufferedInputStream bis = new BufferedInputStream(in);
if (conn == null) throw new IOException();
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
byte[] buffer = new byte[4096];
int len;
while ((len = bis.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.close();
bis.close();
conn.disconnect();
} catch (IOException e) {
e.printStackTrace();
}

View File

@@ -6,7 +6,7 @@ import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.AdaptiveList;
import com.topjohnwu.magisk.container.AdaptiveList;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;

View File

@@ -5,17 +5,23 @@ import android.content.pm.PackageManager;
import android.os.Environment;
import android.widget.Toast;
import com.topjohnwu.jarsigner.JarMap;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.superuser.Policy;
import com.topjohnwu.magisk.container.Policy;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;
import java.io.File;
import java.util.List;
import java.util.jar.JarEntry;
public class HideManager extends ParallelTask<Void, Void, Boolean> {
private static final String UNHIDE_APK = "unhide.apk";
private static final String ANDROID_MANIFEST = "AndroidManifest.xml";
private static final byte[] UNHIDE_PKG_NAME = "com.topjohnwu.unhide\0".getBytes();
public HideManager(Context context) {
super(context);
}
@@ -34,7 +40,42 @@ public class HideManager extends ParallelTask<Void, Void, Boolean> {
// Generate a new unhide app with random package name
File unhideAPK = new File(Environment.getExternalStorageDirectory() + "/MagiskManager", "unhide.apk");
unhideAPK.getParentFile().mkdirs();
String pkg = ZipUtils.generateUnhide(mm, unhideAPK);
String pkg;
try {
JarMap asset = new JarMap(mm.getAssets().open(UNHIDE_APK));
JarEntry je = new JarEntry(ANDROID_MANIFEST);
byte xml[] = asset.getRawData(je);
int offset = -1;
// Linear search pattern offset
for (int i = 0; i < xml.length - UNHIDE_PKG_NAME.length; ++i) {
boolean match = true;
for (int j = 0; j < UNHIDE_PKG_NAME.length; ++j) {
if (xml[i + j] != UNHIDE_PKG_NAME[j]) {
match = false;
break;
}
}
if (match) {
offset = i;
break;
}
}
if (offset < 0)
return false;
// Patch binary XML with new package name
pkg = Utils.genPackageName("com.", UNHIDE_PKG_NAME.length - 1);
System.arraycopy(pkg.getBytes(), 0, xml, offset, pkg.length());
asset.getOutputStream(je).write(xml);
// Sign the APK
ZipUtils.signZip(mm, asset, unhideAPK, false);
} catch (Exception e) {
e.printStackTrace();
return false;
}
// Install the application
List<String> ret = getShell().su("pm install " + unhideAPK + ">/dev/null && echo true || echo false");

View File

@@ -7,9 +7,9 @@ import android.os.Environment;
import android.text.TextUtils;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.utils.AdaptiveList;
import com.topjohnwu.magisk.container.AdaptiveList;
import com.topjohnwu.magisk.container.TarEntry;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.TarEntry;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ZipUtils;

View File

@@ -3,11 +3,9 @@ package com.topjohnwu.magisk.asyncs;
import android.content.Context;
import com.topjohnwu.magisk.MagiskManager;
import com.topjohnwu.magisk.module.BaseModule;
import com.topjohnwu.magisk.module.Module;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.container.Module;
import com.topjohnwu.magisk.container.ValueSortedMap;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.ValueSortedMap;
public class LoadModules extends ParallelTask<Void, Void, Void> {
@@ -19,19 +17,13 @@ public class LoadModules extends ParallelTask<Void, Void, Void> {
protected Void doInBackground(Void... voids) {
MagiskManager mm = getMagiskManager();
if (mm == null) return null;
Logger.dev("LoadModules: Loading modules");
mm.moduleMap = new ValueSortedMap<>();
for (String path : Utils.getModList(getShell(), MagiskManager.MAGISK_PATH)) {
Logger.dev("LoadModules: Adding modules from " + path);
try {
Module module = new Module(getShell(), path);
mm.moduleMap.put(module.getId(), module);
} catch (BaseModule.CacheModException ignored) {}
Module module = new Module(getShell(), path);
mm.moduleMap.put(module.getId(), module);
}
Logger.dev("LoadModules: Data load done");
return null;
}

View File

@@ -6,11 +6,12 @@ import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.widget.Toast;
import com.topjohnwu.magisk.FlashActivity;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.container.InputStreamWrapper;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.magisk.utils.WebService;
@@ -21,36 +22,81 @@ import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
public class ProcessRepoZip extends ParallelTask<Void, Object, Boolean> {
private ProgressDialog progressDialog;
private boolean mInstall;
private String mLink;
private File mFile;
private int progress = 0, total = -1;
private static final int UPDATE_DL_PROG = 0;
private static final int SHOW_PROCESSING = 1;
public ProcessRepoZip(Activity context, String link, String filename, boolean install) {
super(context);
mLink = link;
mFile = new File(Environment.getExternalStorageDirectory() + "/MagiskManager", filename);
mFile.getParentFile().mkdirs();
mInstall = install;
}
private void removeTopFolder(InputStream in, File output) throws IOException {
JarInputStream source = new JarInputStream(in);
JarOutputStream dest = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(output)));
JarEntry entry;
String path;
int size;
byte buffer[] = new byte[4096];
while ((entry = source.getNextJarEntry()) != null) {
// Remove the top directory from the path
path = entry.getName().substring(entry.getName().indexOf("/") + 1);
// If it's the top folder, ignore it
if (path.isEmpty()) {
continue;
}
// Don't include placeholder
if (path.equals("system/placeholder")) {
continue;
}
dest.putNextEntry(new JarEntry(path));
while((size = source.read(buffer)) != -1) {
dest.write(buffer, 0, size);
}
}
source.close();
dest.close();
in.close();
}
@Override
protected void onPreExecute() {
Activity activity = getActivity();
progressDialog = ProgressDialog.show(activity,
activity.getString(R.string.zip_download_title),
activity.getString(R.string.zip_download_msg));
mFile.getParentFile().mkdirs();
progressDialog = ProgressDialog.show(activity, activity.getString(R.string.zip_download_title), activity.getString(R.string.zip_download_msg, 0));
}
@Override
protected void onProgressUpdate(Void... values) {
progressDialog.setTitle(R.string.zip_process_title);
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
protected void onProgressUpdate(Object... values) {
int mode = (int) values[0];
switch (mode) {
case UPDATE_DL_PROG:
int add = (int) values[1];
progress += add;
progressDialog.setMessage(getActivity().getString(R.string.zip_download_msg, 100 * progress / total));
break;
case SHOW_PROCESSING:
progressDialog.setTitle(R.string.zip_process_title);
progressDialog.setMessage(getActivity().getString(R.string.zip_process_msg));
break;
}
}
@Override
@@ -60,9 +106,18 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
try {
// Request zip from Internet
InputStream in = WebService.request(WebService.GET, mLink, null);
if (in == null) return false;
in = new BufferedInputStream(in);
HttpURLConnection conn;
do {
conn = WebService.request(mLink, null);
if (conn == null) return null;
total = conn.getContentLength();
if (total < 0)
conn.disconnect();
else
break;
} while (true);
InputStream in = new BufferedInputStream(new ProgressInputStream(conn.getInputStream()));
// Temp files
File temp1 = new File(activity.getCacheDir(), "1.zip");
@@ -70,9 +125,10 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
temp1.getParentFile().mkdir();
// First remove top folder in Github source zip, Web -> temp1
ZipUtils.removeTopFolder(in, temp1);
removeTopFolder(in, temp1);
publishProgress();
conn.disconnect();
publishProgress(SHOW_PROCESSING);
// Then sign the zip for the first time, temp1 -> temp2
ZipUtils.signZip(activity, temp1, temp2, false);
@@ -99,7 +155,6 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
return true;
} catch (Exception e) {
Logger.error("ProcessRepoZip: Error!");
e.printStackTrace();
return false;
}
@@ -126,8 +181,34 @@ public class ProcessRepoZip extends ParallelTask<Void, Void, Boolean> {
}
@Override
public ParallelTask<Void, Void, Boolean> exec(Void... voids) {
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE, () -> super.exec(voids));
public ParallelTask<Void, Object, Boolean> exec(Void... voids) {
Utils.runWithPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE,
() -> super.exec(voids));
return this;
}
private class ProgressInputStream extends InputStreamWrapper {
ProgressInputStream(InputStream in) {
super(in);
}
@Override
public synchronized int read() throws IOException {
publishProgress(UPDATE_DL_PROG, 1);
return super.read();
}
@Override
public int read(@NonNull byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException {
int read = super.read(b, off, len);
publishProgress(UPDATE_DL_PROG, read);
return read;
}
}
}

View File

@@ -1,4 +1,4 @@
package com.topjohnwu.magisk.utils;
package com.topjohnwu.magisk.container;
import android.support.v7.widget.RecyclerView;

View File

@@ -1,17 +1,16 @@
package com.topjohnwu.magisk.module;
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.database.Cursor;
import android.support.annotation.NonNull;
import com.topjohnwu.magisk.utils.Logger;
import java.util.List;
public abstract class BaseModule implements Comparable<BaseModule> {
private String mId, mName, mVersion, mAuthor, mDescription;
private int mVersionCode = 0, templateVersion = 0;
private String mId = null, mName, mVersion, mAuthor, mDescription;
private int mVersionCode = -1, templateVersion = -1;
protected BaseModule() {}
@@ -25,9 +24,21 @@ public abstract class BaseModule implements Comparable<BaseModule> {
templateVersion = c.getInt(c.getColumnIndex("template"));
}
protected void parseProps(List<String> props) throws CacheModException { parseProps(props.toArray(new String[props.size()])); }
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("id", mId);
values.put("name", mName);
values.put("version", mVersion);
values.put("versionCode", mVersionCode);
values.put("author", mAuthor);
values.put("description", mDescription);
values.put("template", templateVersion);
return values;
}
protected void parseProps(String[] props) throws CacheModException {
protected void parseProps(List<String> props) { parseProps(props.toArray(new String[0])); }
protected void parseProps(String[] props) throws NumberFormatException {
for (String line : props) {
String[] prop = line.split("=", 2);
if (prop.length != 2)
@@ -48,9 +59,7 @@ public abstract class BaseModule implements Comparable<BaseModule> {
mVersion = prop[1];
break;
case "versionCode":
try {
mVersionCode = Integer.parseInt(prop[1]);
} catch (NumberFormatException ignored) {}
mVersionCode = Integer.parseInt(prop[1]);
break;
case "author":
mAuthor = prop[1];
@@ -59,12 +68,7 @@ public abstract class BaseModule implements Comparable<BaseModule> {
mDescription = prop[1];
break;
case "template":
try {
templateVersion = Integer.parseInt(prop[1]);
} catch (NumberFormatException ignored) {}
case "cacheModule":
if (Boolean.parseBoolean(prop[1]))
throw new CacheModException(mId);
templateVersion = Integer.parseInt(prop[1]);
break;
default:
break;
@@ -108,12 +112,6 @@ public abstract class BaseModule implements Comparable<BaseModule> {
return templateVersion;
}
public static class CacheModException extends Exception {
public CacheModException(String id) {
Logger.error("Cache mods are no longer supported! id: " + id);
}
}
@Override
public int compareTo(@NonNull BaseModule module) {
return this.getName().toLowerCase().compareTo(module.getName().toLowerCase());

View File

@@ -0,0 +1,59 @@
package com.topjohnwu.magisk.container;
import android.support.annotation.NonNull;
import java.io.IOException;
import java.io.InputStream;
public class InputStreamWrapper extends InputStream {
private InputStream in;
public InputStreamWrapper(InputStream in) {
this.in = in;
}
@Override
public int available() throws IOException {
return in.available();
}
@Override
public void close() throws IOException {
in.close();
}
@Override
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}
@Override
public boolean markSupported() {
return in.markSupported();
}
@Override
public synchronized int read() throws IOException {
return in.read();
}
@Override
public int read(@NonNull byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public synchronized int read(@NonNull byte[] b, int off, int len) throws IOException {
return in.read(b, off, len);
}
@Override
public synchronized void reset() throws IOException {
in.reset();
}
@Override
public long skip(long n) throws IOException {
return in.skip(n);
}
}

View File

@@ -1,6 +1,5 @@
package com.topjohnwu.magisk.module;
package com.topjohnwu.magisk.container;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.Shell;
import com.topjohnwu.magisk.utils.Utils;
@@ -9,9 +8,11 @@ public class Module extends BaseModule {
private String mRemoveFile, mDisableFile, mUpdateFile;
private boolean mEnable, mRemove, mUpdated;
public Module(Shell shell, String path) throws CacheModException {
public Module(Shell shell, String path) {
parseProps(Utils.readFile(shell, path + "/module.prop"));
try {
parseProps(Utils.readFile(shell, path + "/module.prop"));
} catch (NumberFormatException ignored) {}
mRemoveFile = path + "/remove";
mDisableFile = path + "/disable";
@@ -26,8 +27,6 @@ public class Module extends BaseModule {
setName(getId());
}
Logger.dev("Creating Module, id: " + getId());
mEnable = !Utils.itemExist(shell, mDisableFile);
mRemove = Utils.itemExist(shell, mRemoveFile);
mUpdated = Utils.itemExist(shell, mUpdateFile);

View File

@@ -1,4 +1,4 @@
package com.topjohnwu.magisk.superuser;
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.content.pm.ApplicationInfo;

View File

@@ -1,22 +1,23 @@
package com.topjohnwu.magisk.module;
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.database.Cursor;
import com.topjohnwu.magisk.utils.Logger;
import com.topjohnwu.magisk.utils.WebService;
import java.util.Date;
public class Repo extends BaseModule {
public static final int MIN_TEMPLATE_VER = 4;
private static final String FILE_URL = "https://raw.githubusercontent.com/Magisk-Modules-Repo/%s/master/%s";
private static final String ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip";
private String repoName;
private Date mLastUpdate;
public Repo(String name, Date lastUpdate) throws CacheModException {
public Repo(String name, Date lastUpdate) throws IllegalRepoException {
mLastUpdate = lastUpdate;
repoName = name;
update();
@@ -28,14 +29,27 @@ public class Repo extends BaseModule {
mLastUpdate = new Date(c.getLong(c.getColumnIndex("last_update")));
}
public void update() throws CacheModException {
public void update() throws IllegalRepoException {
String props = WebService.getString(getManifestUrl());
String lines[] = props.split("\\n");
parseProps(lines);
Logger.dev("Repo: Fetching prop: " + getId());
try {
parseProps(lines);
} catch (NumberFormatException e) {
throw new IllegalRepoException("Repo [" + repoName + "] parse error: " + e.getMessage());
}
if (getId() == null) {
throw new IllegalRepoException("Repo [" + repoName + "] does not contain id");
}
if (getVersionCode() < 0) {
throw new IllegalRepoException("Repo [" + repoName + "] does not contain versionCode");
}
if (getTemplateVersion() < MIN_TEMPLATE_VER) {
throw new IllegalRepoException("Repo [" + repoName + "] is outdated");
}
}
public boolean update(Date lastUpdate) throws CacheModException {
public boolean update(Date lastUpdate) throws IllegalRepoException {
if (lastUpdate.after(mLastUpdate)) {
mLastUpdate = lastUpdate;
update();
@@ -45,19 +59,16 @@ public class Repo extends BaseModule {
}
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put("id", getId());
values.put("name", getName());
values.put("version", getVersion());
values.put("versionCode", getVersionCode());
values.put("author", getAuthor());
values.put("description", getDescription());
ContentValues values = super.getContentValues();
values.put("repo_name", repoName);
values.put("last_update", mLastUpdate.getTime());
values.put("template", getTemplateVersion());
return values;
}
public String getRepoName() {
return repoName;
}
public String getZipUrl() {
return String.format(ZIP_URL, repoName);
}
@@ -73,4 +84,10 @@ public class Repo extends BaseModule {
public Date getLastUpdate() {
return mLastUpdate;
}
public class IllegalRepoException extends Exception {
IllegalRepoException(String message) {
super(message);
}
}
}

View File

@@ -1,4 +1,4 @@
package com.topjohnwu.magisk.superuser;
package com.topjohnwu.magisk.container;
import android.content.ContentValues;
import android.database.Cursor;

Some files were not shown because too many files have changed in this diff Show More