Adapt to new EdXposed
This commit is contained in:
parent
b6bdfe508e
commit
abc3598881
|
|
@ -19,6 +19,5 @@
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
-keep class org.meowcat.edxposed.manager.util.json.**{public *; }
|
-keep class org.meowcat.edxposed.manager.util.json.** {public *; }
|
||||||
-keep class org.meowcat.edxposed.manager.xposed.**{ *; }
|
-keep class org.meowcat.edxposed.manager.Constants { *; }
|
||||||
-keep class de.robv.android.xposed.installer.**{public *; }
|
|
||||||
|
|
@ -97,18 +97,6 @@
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/file_paths" />
|
android:resource="@xml/file_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<meta-data
|
|
||||||
android:name="xposedmodule"
|
|
||||||
android:value="true" />
|
|
||||||
|
|
||||||
<meta-data
|
|
||||||
android:name="xposeddescription"
|
|
||||||
android:value="@string/xposed_description" />
|
|
||||||
|
|
||||||
<meta-data
|
|
||||||
android:name="xposedminversion"
|
|
||||||
android:value="82" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
org.meowcat.edxposed.manager.xposed.Enhancement
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
package de.robv.android.xposed.installer;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Application;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import de.robv.android.xposed.installer.util.InstallZipUtil;
|
|
||||||
|
|
||||||
import static de.robv.android.xposed.installer.util.InstallZipUtil.parseXposedProp;
|
|
||||||
|
|
||||||
@SuppressLint("Registered")
|
|
||||||
public class XposedApp extends Application {
|
|
||||||
public static final String TAG = "EdXposedManager";
|
|
||||||
private static final File EDXPOSED_PROP_FILE = new File("/system/framework/edconfig.jar");
|
|
||||||
public InstallZipUtil.XposedProp mXposedProp;
|
|
||||||
|
|
||||||
public static boolean isEnhancementEnabled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is hooked by XposedBridge to return the current version
|
|
||||||
public static Integer getActiveXposedVersion() {
|
|
||||||
Log.d(TAG, "EdXposed is not active");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onCreate() {
|
|
||||||
super.onCreate();
|
|
||||||
reloadXposedProp();
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method is hooked by XposedBridge
|
|
||||||
public void reloadXposedProp() {
|
|
||||||
InstallZipUtil.XposedProp prop = null;
|
|
||||||
File file = null;
|
|
||||||
|
|
||||||
if (EDXPOSED_PROP_FILE.canRead()) {
|
|
||||||
file = EDXPOSED_PROP_FILE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file != null) {
|
|
||||||
try (FileInputStream is = new FileInputStream(file)) {
|
|
||||||
prop = parseXposedProp(is);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "Could not read " + file.getPath(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synchronized (this) {
|
|
||||||
mXposedProp = prop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
package de.robv.android.xposed.installer.util;
|
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.util.ModuleUtil;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
|
|
||||||
public final class InstallZipUtil {
|
|
||||||
|
|
||||||
public static XposedProp parseXposedProp(InputStream is) throws IOException {
|
|
||||||
XposedProp prop = new XposedProp();
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
|
|
||||||
String line;
|
|
||||||
while ((line = reader.readLine()) != null) {
|
|
||||||
String[] parts = line.split("=", 2);
|
|
||||||
if (parts.length != 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String key = parts[0].trim();
|
|
||||||
if (key.charAt(0) == '#') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = parts[1].trim();
|
|
||||||
|
|
||||||
if ("version".equals(key)) {
|
|
||||||
prop.mVersion = value;
|
|
||||||
prop.mVersionInt = ModuleUtil.extractIntPart(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reader.close();
|
|
||||||
return prop.isComplete() ? prop : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class XposedProp {
|
|
||||||
private String mVersion = null;
|
|
||||||
private int mVersionInt = 0;
|
|
||||||
|
|
||||||
private boolean isComplete() {
|
|
||||||
return mVersion != null
|
|
||||||
&& mVersionInt > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return mVersion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -35,12 +35,8 @@ import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import de.robv.android.xposed.installer.XposedApp;
|
public class App extends Application implements Application.ActivityLifecycleCallbacks {
|
||||||
import de.robv.android.xposed.installer.util.InstallZipUtil;
|
public static final String TAG = "EdXposedManager";
|
||||||
|
|
||||||
public class App extends XposedApp implements Application.ActivityLifecycleCallbacks {
|
|
||||||
public static String BASE_DIR = null;
|
|
||||||
public static String ENABLED_MODULES_LIST_FILE = null;
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private static App instance = null;
|
private static App instance = null;
|
||||||
private static Thread uiThread;
|
private static Thread uiThread;
|
||||||
|
|
@ -53,10 +49,6 @@ public class App extends XposedApp implements Application.ActivityLifecycleCallb
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InstallZipUtil.XposedProp getXposedProp() {
|
|
||||||
return getInstance().mXposedProp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void runOnUiThread(Runnable action) {
|
public static void runOnUiThread(Runnable action) {
|
||||||
if (Thread.currentThread() != uiThread) {
|
if (Thread.currentThread() != uiThread) {
|
||||||
mainHandler.post(action);
|
mainHandler.post(action);
|
||||||
|
|
@ -70,14 +62,14 @@ public class App extends XposedApp implements Application.ActivityLifecycleCallb
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void mkdirAndChmod(String dir, int permissions) {
|
public static void mkdirAndChmod(String dir, int permissions) {
|
||||||
dir = BASE_DIR + dir;
|
dir = Constants.getBaseDir() + dir;
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
new File(dir).mkdir();
|
new File(dir).mkdir();
|
||||||
FileUtils.setPermissions(dir, permissions);
|
FileUtils.setPermissions(dir, permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean supportScope() {
|
public static boolean supportScope() {
|
||||||
return App.getActiveXposedVersion() >= 92;
|
return Constants.getXposedApiVersion() >= 92;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
|
|
@ -111,11 +103,6 @@ public class App extends XposedApp implements Application.ActivityLifecycleCallb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ApplicationInfo appInfo = getApplicationInfo();
|
|
||||||
BASE_DIR = appInfo.deviceProtectedDataDir + "/";
|
|
||||||
ENABLED_MODULES_LIST_FILE = BASE_DIR + "conf/enabled_modules.list";
|
|
||||||
ModuleUtil.MODULES_LIST_FILE = BASE_DIR + "conf/modules.list";
|
|
||||||
|
|
||||||
instance = this;
|
instance = this;
|
||||||
uiThread = Thread.currentThread();
|
uiThread = Thread.currentThread();
|
||||||
mainHandler = new Handler();
|
mainHandler = new Handler();
|
||||||
|
|
@ -158,7 +145,7 @@ public class App extends XposedApp implements Application.ActivityLifecycleCallb
|
||||||
@SuppressWarnings({"OctalInteger"})
|
@SuppressWarnings({"OctalInteger"})
|
||||||
@SuppressLint({"PrivateApi", "NewApi"})
|
@SuppressLint({"PrivateApi", "NewApi"})
|
||||||
private void createDirectories() {
|
private void createDirectories() {
|
||||||
FileUtils.setPermissions(BASE_DIR, 00777);
|
FileUtils.setPermissions(Constants.getBaseDir(), 00777);
|
||||||
mkdirAndChmod("conf", 00777);
|
mkdirAndChmod("conf", 00777);
|
||||||
mkdirAndChmod("log", 00777);
|
mkdirAndChmod("log", 00777);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package org.meowcat.edxposed.manager;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
public class Constants {
|
||||||
|
public static int getXposedApiVersion() {
|
||||||
|
Log.e(App.TAG, "getXposedApiVersion: Xposed is not active");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getXposedVersion() {
|
||||||
|
Log.e(App.TAG, "getXposedVersion: Xposed is not active");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getXposedVersionCode() {
|
||||||
|
Log.e(App.TAG, "getXposedVersionCode: Xposed is not active");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getXposedVariant() {
|
||||||
|
Log.e(App.TAG, "getXposedVariant: Xposed is not active");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getEnabledModulesListFile() {
|
||||||
|
return getBaseDir() + "conf/enabled_modules.list";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getModulesListFile() {
|
||||||
|
return getBaseDir() + "conf/modules.list";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getBaseDir() {
|
||||||
|
return App.getInstance().getApplicationInfo().deviceProtectedDataDir + "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,7 @@ import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.App;
|
import org.meowcat.edxposed.manager.App;
|
||||||
import org.meowcat.edxposed.manager.BuildConfig;
|
import org.meowcat.edxposed.manager.BuildConfig;
|
||||||
|
import org.meowcat.edxposed.manager.Constants;
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.util.CompileUtil;
|
import org.meowcat.edxposed.manager.util.CompileUtil;
|
||||||
import org.meowcat.edxposed.manager.util.FileUtils;
|
import org.meowcat.edxposed.manager.util.FileUtils;
|
||||||
|
|
@ -30,7 +31,6 @@ import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -41,9 +41,7 @@ import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS;
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class AppHelper {
|
public class AppHelper {
|
||||||
|
|
||||||
public static final String TAG = App.TAG;
|
private static final String BASE_PATH = Constants.getBaseDir();
|
||||||
|
|
||||||
private static final String BASE_PATH = App.BASE_DIR;
|
|
||||||
private static final String WHITE_LIST_PATH = "conf/whitelist/";
|
private static final String WHITE_LIST_PATH = "conf/whitelist/";
|
||||||
private static final String BLACK_LIST_PATH = "conf/blacklist/";
|
private static final String BLACK_LIST_PATH = "conf/blacklist/";
|
||||||
private static final String COMPAT_LIST_PATH = "conf/compatlist/";
|
private static final String COMPAT_LIST_PATH = "conf/compatlist/";
|
||||||
|
|
@ -51,7 +49,7 @@ public class AppHelper {
|
||||||
private static final String WHITE_LIST_MODE = "conf/usewhitelist";
|
private static final String WHITE_LIST_MODE = "conf/usewhitelist";
|
||||||
private static final String BLACK_LIST_MODE = "conf/blackwhitelist";
|
private static final String BLACK_LIST_MODE = "conf/blackwhitelist";
|
||||||
|
|
||||||
private static final List<String> FORCE_WHITE_LIST = new ArrayList<>(App.isEnhancementEnabled() ? Arrays.asList(BuildConfig.APPLICATION_ID, "android") : Collections.singletonList(BuildConfig.APPLICATION_ID));
|
private static final List<String> FORCE_WHITE_LIST = new ArrayList<>(Collections.singletonList(BuildConfig.APPLICATION_ID));
|
||||||
public static List<String> FORCE_WHITE_LIST_MODULE = new ArrayList<>(FORCE_WHITE_LIST);
|
public static List<String> FORCE_WHITE_LIST_MODULE = new ArrayList<>(FORCE_WHITE_LIST);
|
||||||
|
|
||||||
private static final HashMap<String, List<String>> scopeList = new HashMap<>();
|
private static final HashMap<String, List<String>> scopeList = new HashMap<>();
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.App;
|
import org.meowcat.edxposed.manager.App;
|
||||||
import org.meowcat.edxposed.manager.BuildConfig;
|
import org.meowcat.edxposed.manager.BuildConfig;
|
||||||
|
import org.meowcat.edxposed.manager.Constants;
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.databinding.ActivityLogsBinding;
|
import org.meowcat.edxposed.manager.databinding.ActivityLogsBinding;
|
||||||
import org.meowcat.edxposed.manager.databinding.DialogInstallWarningBinding;
|
import org.meowcat.edxposed.manager.databinding.DialogInstallWarningBinding;
|
||||||
|
|
@ -44,11 +45,11 @@ import java.util.Scanner;
|
||||||
|
|
||||||
public class LogsActivity extends BaseActivity {
|
public class LogsActivity extends BaseActivity {
|
||||||
private boolean allLog = false;
|
private boolean allLog = false;
|
||||||
private final File fileErrorLog = new File(App.BASE_DIR + "log/error.log");
|
private final File fileErrorLog = new File(Constants.getBaseDir() + "log/error.log");
|
||||||
private final File fileErrorLogOld = new File(
|
private final File fileErrorLogOld = new File(
|
||||||
App.BASE_DIR + "log/error.log.old");
|
Constants.getBaseDir() + "log/error.log.old");
|
||||||
private final File fileAllLog = new File(App.BASE_DIR + "log/all.log");
|
private final File fileAllLog = new File(Constants.getBaseDir() + "log/all.log");
|
||||||
private final File fileAllLogOld = new File(App.BASE_DIR + "log/all.log.old");
|
private final File fileAllLogOld = new File(Constants.getBaseDir() + "log/all.log.old");
|
||||||
private LogsAdapter adapter;
|
private LogsAdapter adapter;
|
||||||
private final Handler handler = new Handler();
|
private final Handler handler = new Handler();
|
||||||
private ActivityLogsBinding binding;
|
private ActivityLogsBinding binding;
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat;
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.App;
|
import org.meowcat.edxposed.manager.App;
|
||||||
|
import org.meowcat.edxposed.manager.Constants;
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.adapters.AppHelper;
|
import org.meowcat.edxposed.manager.adapters.AppHelper;
|
||||||
import org.meowcat.edxposed.manager.adapters.BlackListAdapter;
|
import org.meowcat.edxposed.manager.adapters.BlackListAdapter;
|
||||||
|
|
@ -86,18 +87,11 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene
|
||||||
Glide.with(binding.appIcon)
|
Glide.with(binding.appIcon)
|
||||||
.load(GlideHelper.wrapApplicationInfoForIconLoader(getApplicationInfo()))
|
.load(GlideHelper.wrapApplicationInfoForIconLoader(getApplicationInfo()))
|
||||||
.into(binding.appIcon);
|
.into(binding.appIcon);
|
||||||
String installedXposedVersion;
|
String installedXposedVersion = Constants.getXposedVersion();
|
||||||
try {
|
|
||||||
installedXposedVersion = App.getXposedProp().getVersion();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
installedXposedVersion = null;
|
|
||||||
}
|
|
||||||
if (installedXposedVersion != null) {
|
if (installedXposedVersion != null) {
|
||||||
int installedXposedVersionInt = extractIntPart(installedXposedVersion);
|
if (Constants.getXposedApiVersion() != -1) {
|
||||||
if (App.getActiveXposedVersion() != -1) {
|
|
||||||
String installedXposedVersionStr = installedXposedVersionInt + ".0";
|
|
||||||
binding.statusTitle.setText(R.string.Activated);
|
binding.statusTitle.setText(R.string.Activated);
|
||||||
binding.statusSummary.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
|
binding.statusSummary.setText(installedXposedVersion + " (" + Constants.getXposedVariant() + ")");
|
||||||
binding.status.setCardBackgroundColor(ContextCompat.getColor(this, R.color.download_status_update_available));
|
binding.status.setCardBackgroundColor(ContextCompat.getColor(this, R.color.download_status_update_available));
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_check_circle);
|
binding.statusIcon.setImageResource(R.drawable.ic_check_circle);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -106,9 +100,9 @@ public class MainActivity extends BaseActivity implements RepoLoader.RepoListene
|
||||||
binding.status.setCardBackgroundColor(ContextCompat.getColor(this, R.color.amber_500));
|
binding.status.setCardBackgroundColor(ContextCompat.getColor(this, R.color.amber_500));
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_warning);
|
binding.statusIcon.setImageResource(R.drawable.ic_warning);
|
||||||
}
|
}
|
||||||
} else if (App.getActiveXposedVersion() > 0) {
|
} else if (Constants.getXposedApiVersion() > 0) {
|
||||||
binding.statusTitle.setText(R.string.Activated);
|
binding.statusTitle.setText(R.string.Activated);
|
||||||
binding.statusSummary.setText(getString(R.string.version_x, App.getActiveXposedVersion()));
|
binding.statusSummary.setText(getString(R.string.version_x, Constants.getXposedApiVersion()));
|
||||||
binding.status.setCardBackgroundColor(ContextCompat.getColor(this, R.color.download_status_update_available));
|
binding.status.setCardBackgroundColor(ContextCompat.getColor(this, R.color.download_status_update_available));
|
||||||
binding.statusIcon.setImageResource(R.drawable.ic_check_circle);
|
binding.statusIcon.setImageResource(R.drawable.ic_check_circle);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.App;
|
import org.meowcat.edxposed.manager.App;
|
||||||
import org.meowcat.edxposed.manager.BuildConfig;
|
import org.meowcat.edxposed.manager.BuildConfig;
|
||||||
|
import org.meowcat.edxposed.manager.Constants;
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.databinding.ActivityModulesBinding;
|
import org.meowcat.edxposed.manager.databinding.ActivityModulesBinding;
|
||||||
import org.meowcat.edxposed.manager.repo.Module;
|
import org.meowcat.edxposed.manager.repo.Module;
|
||||||
|
|
@ -191,7 +192,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
pm = getPackageManager();
|
pm = getPackageManager();
|
||||||
displayNameComparator = new ApplicationInfo.DisplayNameComparator(pm);
|
displayNameComparator = new ApplicationInfo.DisplayNameComparator(pm);
|
||||||
cmp = displayNameComparator;
|
cmp = displayNameComparator;
|
||||||
installedXposedVersion = App.getActiveXposedVersion();
|
installedXposedVersion = Constants.getXposedApiVersion();
|
||||||
if (installedXposedVersion <= 0) {
|
if (installedXposedVersion <= 0) {
|
||||||
Snackbar.make(binding.snackbar, R.string.xposed_not_active, Snackbar.LENGTH_LONG).setAction(R.string.Settings, v -> {
|
Snackbar.make(binding.snackbar, R.string.xposed_not_active, Snackbar.LENGTH_LONG).setAction(R.string.Settings, v -> {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
|
|
@ -246,7 +247,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (requestCode == 42) {
|
if (requestCode == 42) {
|
||||||
File listModules = new File(App.ENABLED_MODULES_LIST_FILE);
|
File listModules = new File(Constants.getEnabledModulesListFile());
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
Uri uri = data.getData();
|
Uri uri = data.getData();
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import com.takisoft.preferencex.PreferenceFragmentCompat;
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.Shell;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.App;
|
import org.meowcat.edxposed.manager.App;
|
||||||
|
import org.meowcat.edxposed.manager.Constants;
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.adapters.AppHelper;
|
import org.meowcat.edxposed.manager.adapters.AppHelper;
|
||||||
import org.meowcat.edxposed.manager.adapters.BlackListAdapter;
|
import org.meowcat.edxposed.manager.adapters.BlackListAdapter;
|
||||||
|
|
@ -114,18 +115,15 @@ public class SettingsActivity extends BaseActivity {
|
||||||
|
|
||||||
@SuppressWarnings({"ResultOfMethodCallIgnored", "deprecation"})
|
@SuppressWarnings({"ResultOfMethodCallIgnored", "deprecation"})
|
||||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||||
private static final File pretendXposedInstallerFlag = new File(App.BASE_DIR + "conf/pretend_xposed_installer");
|
private static final File disableResourcesFlag = new File(Constants.getBaseDir() + "conf/disable_resources");
|
||||||
private static final File hideEdXposedManagerFlag = new File(App.BASE_DIR + "conf/hide_edxposed_manager");
|
private static final File dynamicModulesFlag = new File(Constants.getBaseDir() + "conf/dynamicmodules");
|
||||||
private static final File disableHiddenAPIBypassFlag = new File(App.BASE_DIR + "conf/disable_hidden_api_bypass");
|
private static final File deoptBootFlag = new File(Constants.getBaseDir() + "conf/deoptbootimage");
|
||||||
private static final File disableResourcesFlag = new File(App.BASE_DIR + "conf/disable_resources");
|
private static final File whiteListModeFlag = new File(Constants.getBaseDir() + "conf/usewhitelist");
|
||||||
private static final File dynamicModulesFlag = new File(App.BASE_DIR + "conf/dynamicmodules");
|
private static final File blackWhiteListModeFlag = new File(Constants.getBaseDir() + "conf/blackwhitelist");
|
||||||
private static final File deoptBootFlag = new File(App.BASE_DIR + "conf/deoptbootimage");
|
private static final File disableVerboseLogsFlag = new File(Constants.getBaseDir() + "conf/disable_verbose_log");
|
||||||
private static final File whiteListModeFlag = new File(App.BASE_DIR + "conf/usewhitelist");
|
private static final File disableModulesLogsFlag = new File(Constants.getBaseDir() + "conf/disable_modules_log");
|
||||||
private static final File blackWhiteListModeFlag = new File(App.BASE_DIR + "conf/blackwhitelist");
|
private static final File verboseLogProcessID = new File(Constants.getBaseDir() + "log/all.pid");
|
||||||
private static final File disableVerboseLogsFlag = new File(App.BASE_DIR + "conf/disable_verbose_log");
|
private static final File modulesLogProcessID = new File(Constants.getBaseDir() + "log/error.pid");
|
||||||
private static final File disableModulesLogsFlag = new File(App.BASE_DIR + "conf/disable_modules_log");
|
|
||||||
private static final File verboseLogProcessID = new File(App.BASE_DIR + "log/all.pid");
|
|
||||||
private static final File modulesLogProcessID = new File(App.BASE_DIR + "log/error.pid");
|
|
||||||
|
|
||||||
@SuppressLint({"WorldReadableFiles", "WorldWriteableFiles"})
|
@SuppressLint({"WorldReadableFiles", "WorldWriteableFiles"})
|
||||||
static void setFilePermissionsFromMode(String name) {
|
static void setFilePermissionsFromMode(String name) {
|
||||||
|
|
@ -492,105 +490,6 @@ public class SettingsActivity extends BaseActivity {
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
updatePreference(!md2.isChecked());
|
updatePreference(!md2.isChecked());
|
||||||
|
|
||||||
Preference enhancement_status = findPreference("enhancement_status");
|
|
||||||
Objects.requireNonNull(enhancement_status).setSummary(App.isEnhancementEnabled() ? R.string.settings_summary_enhancement_enabled : R.string.settings_summary_enhancement);
|
|
||||||
SwitchPreferenceCompat prefPretendXposedInstaller = findPreference("pretend_xposed_installer");
|
|
||||||
|
|
||||||
Objects.requireNonNull(prefPretendXposedInstaller).setChecked(pretendXposedInstallerFlag.exists());
|
|
||||||
prefPretendXposedInstaller.setOnPreferenceChangeListener((preference, newValue) -> {
|
|
||||||
boolean enabled = (Boolean) newValue;
|
|
||||||
if (enabled) {
|
|
||||||
new BlackListAdapter(getContext(), AppHelper.isWhiteListMode()).generateCheckedList();
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
|
||||||
fos = new FileOutputStream(pretendXposedInstallerFlag.getPath());
|
|
||||||
setFilePermissionsFromMode(pretendXposedInstallerFlag.getPath());
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
} finally {
|
|
||||||
if (fos != null) {
|
|
||||||
try {
|
|
||||||
fos.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
try {
|
|
||||||
pretendXposedInstallerFlag.createNewFile();
|
|
||||||
} catch (IOException e1) {
|
|
||||||
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pretendXposedInstallerFlag.delete();
|
|
||||||
}
|
|
||||||
return (enabled == pretendXposedInstallerFlag.exists());
|
|
||||||
});
|
|
||||||
|
|
||||||
SwitchPreferenceCompat prefHideEdXposedManager = findPreference("hide_edxposed_manager");
|
|
||||||
Objects.requireNonNull(prefHideEdXposedManager).setChecked(hideEdXposedManagerFlag.exists());
|
|
||||||
prefHideEdXposedManager.setOnPreferenceChangeListener((preference, newValue) -> {
|
|
||||||
boolean enabled = (Boolean) newValue;
|
|
||||||
if (enabled) {
|
|
||||||
new BlackListAdapter(getContext(), AppHelper.isWhiteListMode()).generateCheckedList();
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
|
||||||
fos = new FileOutputStream(hideEdXposedManagerFlag.getPath());
|
|
||||||
setFilePermissionsFromMode(hideEdXposedManagerFlag.getPath());
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
} finally {
|
|
||||||
if (fos != null) {
|
|
||||||
try {
|
|
||||||
fos.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
try {
|
|
||||||
hideEdXposedManagerFlag.createNewFile();
|
|
||||||
} catch (IOException e1) {
|
|
||||||
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hideEdXposedManagerFlag.delete();
|
|
||||||
}
|
|
||||||
return (enabled == hideEdXposedManagerFlag.exists());
|
|
||||||
});
|
|
||||||
|
|
||||||
SwitchPreferenceCompat prefDisableHiddenAPIBypass = findPreference("disable_hidden_api_bypass");
|
|
||||||
Objects.requireNonNull(prefDisableHiddenAPIBypass).setChecked(disableHiddenAPIBypassFlag.exists());
|
|
||||||
prefDisableHiddenAPIBypass.setOnPreferenceChangeListener((preference, newValue) -> {
|
|
||||||
boolean enabled = (Boolean) newValue;
|
|
||||||
if (enabled) {
|
|
||||||
FileOutputStream fos = null;
|
|
||||||
try {
|
|
||||||
fos = new FileOutputStream(disableHiddenAPIBypassFlag.getPath());
|
|
||||||
setFilePermissionsFromMode(disableHiddenAPIBypassFlag.getPath());
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
} finally {
|
|
||||||
if (fos != null) {
|
|
||||||
try {
|
|
||||||
fos.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
try {
|
|
||||||
disableHiddenAPIBypassFlag.createNewFile();
|
|
||||||
} catch (IOException e1) {
|
|
||||||
Toast.makeText(getActivity(), e1.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
disableHiddenAPIBypassFlag.delete();
|
|
||||||
}
|
|
||||||
return (enabled == disableHiddenAPIBypassFlag.exists());
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.App;
|
import org.meowcat.edxposed.manager.App;
|
||||||
import org.meowcat.edxposed.manager.BuildConfig;
|
import org.meowcat.edxposed.manager.BuildConfig;
|
||||||
|
import org.meowcat.edxposed.manager.Constants;
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.databinding.StatusInstallerBinding;
|
import org.meowcat.edxposed.manager.databinding.StatusInstallerBinding;
|
||||||
|
|
||||||
|
|
@ -99,25 +100,12 @@ public class StatusInstallerFragment extends Fragment {
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
binding = StatusInstallerBinding.inflate(inflater, container, false);
|
binding = StatusInstallerBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
String installedXposedVersion;
|
String installedXposedVersion = Constants.getXposedVersion();
|
||||||
try {
|
String mAppVer = String.format("v%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE);
|
||||||
installedXposedVersion = App.getXposedProp().getVersion();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
installedXposedVersion = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String mAppVer;
|
|
||||||
if (App.isEnhancementEnabled()) {
|
|
||||||
mAppVer = String.format("v%s (%s) (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, getString(R.string.status_enhancement));
|
|
||||||
} else {
|
|
||||||
mAppVer = String.format("v%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE);
|
|
||||||
}
|
|
||||||
binding.manager.setText(mAppVer);
|
binding.manager.setText(mAppVer);
|
||||||
if (installedXposedVersion != null) {
|
if (installedXposedVersion != null) {
|
||||||
int installedXposedVersionInt = extractIntPart(installedXposedVersion);
|
binding.api.setText(Constants.getXposedApiVersion() + ".0");
|
||||||
String installedXposedVersionStr = installedXposedVersionInt + ".0";
|
binding.framework.setText(installedXposedVersion + " (" + Constants.getXposedVariant() + ")");
|
||||||
binding.api.setText(installedXposedVersionStr);
|
|
||||||
binding.framework.setText(installedXposedVersion.replace(installedXposedVersionStr + "-", ""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.androidVersion.setText(getString(R.string.android_sdk, getAndroidVersion(), Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
|
binding.androidVersion.setText(getString(R.string.android_sdk, getAndroidVersion(), Build.VERSION.RELEASE, Build.VERSION.SDK_INT));
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import androidx.annotation.NonNull;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.meowcat.edxposed.manager.App;
|
import org.meowcat.edxposed.manager.App;
|
||||||
|
import org.meowcat.edxposed.manager.Constants;
|
||||||
import org.meowcat.edxposed.manager.R;
|
import org.meowcat.edxposed.manager.R;
|
||||||
import org.meowcat.edxposed.manager.databinding.ActivityModulesBinding;
|
import org.meowcat.edxposed.manager.databinding.ActivityModulesBinding;
|
||||||
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
import org.meowcat.edxposed.manager.repo.ModuleVersion;
|
||||||
|
|
@ -32,7 +33,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
public final class ModuleUtil {
|
public final class ModuleUtil {
|
||||||
private static final String PLAY_STORE_PACKAGE = "com.android.vending";
|
private static final String PLAY_STORE_PACKAGE = "com.android.vending";
|
||||||
// xposedminversion below this
|
// xposedminversion below this
|
||||||
public static String MODULES_LIST_FILE = App.BASE_DIR + "conf/modules.list";
|
|
||||||
public static int MIN_MODULE_VERSION = 2; // reject modules with
|
public static int MIN_MODULE_VERSION = 2; // reject modules with
|
||||||
private static ModuleUtil instance = null;
|
private static ModuleUtil instance = null;
|
||||||
private final PackageManager pm;
|
private final PackageManager pm;
|
||||||
|
|
@ -212,7 +212,7 @@ public final class ModuleUtil {
|
||||||
public synchronized void updateModulesList(boolean showToast, ActivityModulesBinding binding) {
|
public synchronized void updateModulesList(boolean showToast, ActivityModulesBinding binding) {
|
||||||
try {
|
try {
|
||||||
Log.i(App.TAG, "ModuleUtil -> updating modules.list");
|
Log.i(App.TAG, "ModuleUtil -> updating modules.list");
|
||||||
int installedXposedVersion = App.getActiveXposedVersion();
|
int installedXposedVersion = Constants.getXposedApiVersion();
|
||||||
if (!App.getPreferences().getBoolean("skip_xposedminversion_check", false) && installedXposedVersion <= 0 && showToast) {
|
if (!App.getPreferences().getBoolean("skip_xposedminversion_check", false) && installedXposedVersion <= 0 && showToast) {
|
||||||
if (binding != null) {
|
if (binding != null) {
|
||||||
Snackbar.make(binding.snackbar, R.string.notinstalled, Snackbar.LENGTH_SHORT).show();
|
Snackbar.make(binding.snackbar, R.string.notinstalled, Snackbar.LENGTH_SHORT).show();
|
||||||
|
|
@ -222,8 +222,8 @@ public final class ModuleUtil {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintWriter modulesList = new PrintWriter(MODULES_LIST_FILE);
|
PrintWriter modulesList = new PrintWriter(Constants.getModulesListFile());
|
||||||
PrintWriter enabledModulesList = new PrintWriter(App.ENABLED_MODULES_LIST_FILE);
|
PrintWriter enabledModulesList = new PrintWriter(Constants.getEnabledModulesListFile());
|
||||||
List<InstalledModule> enabledModules = getEnabledModules();
|
List<InstalledModule> enabledModules = getEnabledModules();
|
||||||
for (InstalledModule module : enabledModules) {
|
for (InstalledModule module : enabledModules) {
|
||||||
|
|
||||||
|
|
@ -248,8 +248,8 @@ public final class ModuleUtil {
|
||||||
modulesList.close();
|
modulesList.close();
|
||||||
enabledModulesList.close();
|
enabledModulesList.close();
|
||||||
|
|
||||||
FileUtils.setPermissions(MODULES_LIST_FILE, 00664);
|
FileUtils.setPermissions(Constants.getEnabledModulesListFile(), 00664);
|
||||||
FileUtils.setPermissions(App.ENABLED_MODULES_LIST_FILE, 00664);
|
FileUtils.setPermissions(Constants.getEnabledModulesListFile(), 00664);
|
||||||
|
|
||||||
if (showToast) {
|
if (showToast) {
|
||||||
if (binding != null) {
|
if (binding != null) {
|
||||||
|
|
@ -259,11 +259,11 @@ public final class ModuleUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(App.TAG, "ModuleUtil -> cannot write " + MODULES_LIST_FILE, e);
|
Log.e(App.TAG, "ModuleUtil -> cannot write " + Constants.getModulesListFile(), e);
|
||||||
if (binding != null) {
|
if (binding != null) {
|
||||||
Snackbar.make(binding.snackbar, "cannot write " + MODULES_LIST_FILE + e, Snackbar.LENGTH_SHORT).show();
|
Snackbar.make(binding.snackbar, "cannot write " + Constants.getModulesListFile() + e, Snackbar.LENGTH_SHORT).show();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(App.getInstance(), "cannot write " + MODULES_LIST_FILE + e, Toast.LENGTH_SHORT).show();
|
Toast.makeText(App.getInstance(), "cannot write " + Constants.getModulesListFile() + e, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -332,7 +332,7 @@ public final class ModuleUtil {
|
||||||
this.minVersion = 0;
|
this.minVersion = 0;
|
||||||
this.description = "";
|
this.description = "";
|
||||||
} else {
|
} else {
|
||||||
int version = App.getActiveXposedVersion();
|
int version = Constants.getXposedApiVersion();
|
||||||
if (version > 0 && App.getPreferences().getBoolean("skip_xposedminversion_check", false)) {
|
if (version > 0 && App.getPreferences().getBoolean("skip_xposedminversion_check", false)) {
|
||||||
this.minVersion = version;
|
this.minVersion = version;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,354 +0,0 @@
|
||||||
package org.meowcat.edxposed.manager.xposed;
|
|
||||||
|
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.FileObserver;
|
|
||||||
import android.os.StrictMode;
|
|
||||||
import android.os.UserHandle;
|
|
||||||
import android.util.SparseArray;
|
|
||||||
|
|
||||||
import androidx.annotation.Keep;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.robv.android.xposed.IXposedHookLoadPackage;
|
|
||||||
import de.robv.android.xposed.XC_MethodHook;
|
|
||||||
import de.robv.android.xposed.XC_MethodReplacement;
|
|
||||||
import de.robv.android.xposed.XposedBridge;
|
|
||||||
import de.robv.android.xposed.XposedHelpers;
|
|
||||||
import de.robv.android.xposed.callbacks.XC_LoadPackage;
|
|
||||||
import de.robv.android.xposed.installer.XposedApp;
|
|
||||||
|
|
||||||
import static de.robv.android.xposed.XposedHelpers.callMethod;
|
|
||||||
import static de.robv.android.xposed.XposedHelpers.callStaticMethod;
|
|
||||||
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
|
|
||||||
import static java.util.Collections.binarySearch;
|
|
||||||
import static org.meowcat.edxposed.manager.BuildConfig.APPLICATION_ID;
|
|
||||||
|
|
||||||
@Keep
|
|
||||||
public class Enhancement implements IXposedHookLoadPackage {
|
|
||||||
|
|
||||||
private static final String mPretendXposedInstallerFlag = "pretend_xposed_installer";
|
|
||||||
private static final String mHideEdXposedManagerFlag = "hide_edxposed_manager";
|
|
||||||
|
|
||||||
private static final String LEGACY_INSTALLER = "de.robv.android.xposed.installer";
|
|
||||||
|
|
||||||
private static final List<String> HIDE_WHITE_LIST = Arrays.asList( // TODO: more whitelist packages
|
|
||||||
APPLICATION_ID, // Whitelist or crash
|
|
||||||
LEGACY_INSTALLER, // for safety
|
|
||||||
"com.android.providers.downloads", // For download modules
|
|
||||||
"com.android.providers.downloads.ui",
|
|
||||||
"com.android.packageinstaller", // For uninstall EdXposed Manager
|
|
||||||
"com.google.android.packageinstaller",
|
|
||||||
"com.android.systemui", // For notifications
|
|
||||||
"com.android.permissioncontroller", // For permissions grant
|
|
||||||
"com.topjohnwu.magisk", // For superuser root grant
|
|
||||||
"eu.chainfire.supersu"
|
|
||||||
); // UserHandle.isCore(uid) will auto pass
|
|
||||||
|
|
||||||
private static final SparseArray<List<String>> modulesList = new SparseArray<>();
|
|
||||||
private static final SparseArray<FileObserver> modulesListObservers = new SparseArray<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
Collections.sort(HIDE_WHITE_LIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean getFlagState(int user, String flag) {
|
|
||||||
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
|
|
||||||
try {
|
|
||||||
return new File(String.format("/data/user_de/%s/%s/conf/%s", user, APPLICATION_ID, flag)).exists();
|
|
||||||
} finally {
|
|
||||||
StrictMode.setThreadPolicy(oldPolicy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> getModulesList(final int user) {
|
|
||||||
final int index = modulesList.indexOfKey(user);
|
|
||||||
if (index >= 0) {
|
|
||||||
return modulesList.valueAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String filename = String.format("/data/user_de/%s/%s/conf/enabled_modules.list", user, APPLICATION_ID);
|
|
||||||
final FileObserver observer = new FileObserver(filename) {
|
|
||||||
@Override
|
|
||||||
public void onEvent(int event, @Nullable String path) {
|
|
||||||
switch (event) {
|
|
||||||
case FileObserver.MODIFY:
|
|
||||||
modulesList.put(user, readModulesList(filename));
|
|
||||||
break;
|
|
||||||
case FileObserver.MOVED_FROM:
|
|
||||||
case FileObserver.MOVED_TO:
|
|
||||||
case FileObserver.MOVE_SELF:
|
|
||||||
case FileObserver.DELETE:
|
|
||||||
case FileObserver.DELETE_SELF:
|
|
||||||
modulesList.remove(user);
|
|
||||||
modulesListObservers.remove(user);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
modulesListObservers.put(user, observer);
|
|
||||||
final List<String> list = readModulesList(filename);
|
|
||||||
modulesList.put(user, list);
|
|
||||||
observer.startWatching();
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> readModulesList(final String filename) {
|
|
||||||
XposedBridge.log("EdXposedManager: Reading modules list " + filename + "...");
|
|
||||||
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
|
|
||||||
try {
|
|
||||||
final File listFile = new File(filename);
|
|
||||||
final List<String> list = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
final FileReader fileReader = new FileReader(listFile);
|
|
||||||
final BufferedReader bufferedReader = new BufferedReader(fileReader);
|
|
||||||
String str;
|
|
||||||
while ((str = bufferedReader.readLine()) != null) {
|
|
||||||
list.add(str);
|
|
||||||
}
|
|
||||||
bufferedReader.close();
|
|
||||||
fileReader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
XposedBridge.log(e);
|
|
||||||
}
|
|
||||||
Collections.sort(list);
|
|
||||||
return list;
|
|
||||||
} finally {
|
|
||||||
StrictMode.setThreadPolicy(oldPolicy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void hookAllMethods(String className, ClassLoader classLoader, String methodName, XC_MethodHook callback) {
|
|
||||||
try {
|
|
||||||
final Class<?> hookClass = XposedHelpers.findClassIfExists(className, classLoader);
|
|
||||||
if (hookClass == null || XposedBridge.hookAllMethods(hookClass, methodName, callback).size() == 0)
|
|
||||||
XposedBridge.log("Failed to hook " + methodName + " method in " + className);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
XposedBridge.log(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
|
|
||||||
if (lpparam.packageName.equals("android")) {
|
|
||||||
// com.android.server.pm.PackageManagerService.getInstalledApplications(int flag, int userId)
|
|
||||||
findAndHookMethod("com.android.server.pm.PackageManagerService", lpparam.classLoader, "getInstalledApplications", int.class, int.class, new XC_MethodHook() {
|
|
||||||
@Override
|
|
||||||
protected void afterHookedMethod(MethodHookParam param) {
|
|
||||||
if (param.args != null && param.args[0] != null) {
|
|
||||||
final int packageUid = Binder.getCallingUid();
|
|
||||||
if ((boolean) callStaticMethod(UserHandle.class, "isCore", packageUid)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int userId = (int) param.args[1];
|
|
||||||
boolean isXposedModule = false;
|
|
||||||
final String[] packages = (String[]) callMethod(param.thisObject, "getPackagesForUid", packageUid);
|
|
||||||
if (packages == null || packages.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (String packageName : packages) {
|
|
||||||
if (binarySearch(HIDE_WHITE_LIST, packageName) >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (binarySearch(getModulesList(userId), packageName) >= 0) {
|
|
||||||
isXposedModule = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") final List<ApplicationInfo> applicationInfoList = (List<ApplicationInfo>) callMethod(param.getResult(), "getList");
|
|
||||||
if (isXposedModule) {
|
|
||||||
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
|
|
||||||
for (ApplicationInfo applicationInfo : applicationInfoList) {
|
|
||||||
if (applicationInfo.packageName.equals(APPLICATION_ID)) {
|
|
||||||
applicationInfo.packageName = LEGACY_INSTALLER;
|
|
||||||
applicationInfoList.add(applicationInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
|
|
||||||
for (ApplicationInfo applicationInfo : applicationInfoList) {
|
|
||||||
if (applicationInfo.packageName.equals(APPLICATION_ID) || applicationInfo.packageName.equals(LEGACY_INSTALLER)) {
|
|
||||||
applicationInfoList.remove(applicationInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
param.setResult(param.getResult()); // "reset" the result to indicate that we handled it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// com.android.server.pm.PackageManagerService.getInstalledPackages(int flag, int userId)
|
|
||||||
findAndHookMethod("com.android.server.pm.PackageManagerService", lpparam.classLoader, "getInstalledPackages", int.class, int.class, new XC_MethodHook() {
|
|
||||||
@Override
|
|
||||||
protected void afterHookedMethod(MethodHookParam param) {
|
|
||||||
if (param.args != null && param.args[0] != null) {
|
|
||||||
final int packageUid = Binder.getCallingUid();
|
|
||||||
if ((boolean) callStaticMethod(UserHandle.class, "isCore", packageUid)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int userId = (int) param.args[1];
|
|
||||||
boolean isXposedModule = false;
|
|
||||||
final String[] packages = (String[]) callMethod(param.thisObject, "getPackagesForUid", packageUid);
|
|
||||||
if (packages == null || packages.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (String packageName : packages) {
|
|
||||||
if (binarySearch(HIDE_WHITE_LIST, packageName) >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (binarySearch(getModulesList(userId), packageName) >= 0) {
|
|
||||||
isXposedModule = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") final List<PackageInfo> packageInfoList = (List<PackageInfo>) callMethod(param.getResult(), "getList");
|
|
||||||
if (isXposedModule) {
|
|
||||||
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
|
|
||||||
for (PackageInfo packageInfo : packageInfoList) {
|
|
||||||
if (packageInfo.packageName.equals(APPLICATION_ID)) {
|
|
||||||
packageInfo.packageName = LEGACY_INSTALLER;
|
|
||||||
packageInfoList.add(packageInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
|
|
||||||
for (PackageInfo packageInfo : packageInfoList) {
|
|
||||||
if (packageInfo.packageName.equals(APPLICATION_ID) || packageInfo.packageName.equals(LEGACY_INSTALLER)) {
|
|
||||||
packageInfoList.remove(packageInfo);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
param.setResult(param.getResult()); // "reset" the result to indicate that we handled it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// com.android.server.pm.PackageManagerService.getApplicationInfo(String packageName, int flag, int userId)
|
|
||||||
hookAllMethods("com.android.server.pm.PackageManagerService", lpparam.classLoader, "getApplicationInfo", new XC_MethodHook() {
|
|
||||||
@Override
|
|
||||||
protected void beforeHookedMethod(MethodHookParam param) {
|
|
||||||
if (param.args != null && param.args[0] != null) {
|
|
||||||
final int packageUid = Binder.getCallingUid();
|
|
||||||
if ((boolean) callStaticMethod(UserHandle.class, "isCore", packageUid)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int userId = (int) param.args[2];
|
|
||||||
boolean isXposedModule = false;
|
|
||||||
final String[] packages = (String[]) callMethod(param.thisObject, "getPackagesForUid", packageUid);
|
|
||||||
if (packages == null || packages.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (String packageName : packages) {
|
|
||||||
if (binarySearch(HIDE_WHITE_LIST, packageName) >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (binarySearch(getModulesList(userId), packageName) >= 0) {
|
|
||||||
isXposedModule = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isXposedModule) {
|
|
||||||
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
|
|
||||||
if (param.args[0].equals(LEGACY_INSTALLER)) {
|
|
||||||
param.args[0] = APPLICATION_ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
|
|
||||||
if (param.args[0].equals(APPLICATION_ID) || param.args[0].equals(LEGACY_INSTALLER)) {
|
|
||||||
param.setResult(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// com.android.server.pm.PackageManagerService.getPackageInfo(String packageName, int flag, int userId)
|
|
||||||
hookAllMethods("com.android.server.pm.PackageManagerService", lpparam.classLoader, "getPackageInfo", new XC_MethodHook() {
|
|
||||||
@Override
|
|
||||||
protected void beforeHookedMethod(MethodHookParam param) {
|
|
||||||
if (param.args != null && param.args[0] != null) {
|
|
||||||
final int packageUid = Binder.getCallingUid();
|
|
||||||
if ((boolean) callStaticMethod(UserHandle.class, "isCore", packageUid)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int userId = (int) param.args[2];
|
|
||||||
boolean isXposedModule = false;
|
|
||||||
final String[] packages = (String[]) callMethod(param.thisObject, "getPackagesForUid", packageUid);
|
|
||||||
if (packages == null || packages.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (String packageName : packages) {
|
|
||||||
if (binarySearch(HIDE_WHITE_LIST, packageName) >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (binarySearch(getModulesList(userId), packageName) >= 0) {
|
|
||||||
isXposedModule = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isXposedModule) {
|
|
||||||
if (getFlagState(userId, mPretendXposedInstallerFlag)) {
|
|
||||||
if (param.args[0].equals(LEGACY_INSTALLER)) {
|
|
||||||
param.args[0] = APPLICATION_ID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (getFlagState(userId, mHideEdXposedManagerFlag)) {
|
|
||||||
if (param.args[0].equals(APPLICATION_ID) || param.args[0].equals(LEGACY_INSTALLER)) {
|
|
||||||
param.setResult(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Hook AM to remove restrict of EdXposed Manager
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
final XC_MethodHook hook = new XC_MethodHook() {
|
|
||||||
@Override
|
|
||||||
protected void afterHookedMethod(MethodHookParam param) {
|
|
||||||
if (param.args != null && param.args[1] != null) {
|
|
||||||
if (param.args[1].equals(APPLICATION_ID)) {
|
|
||||||
param.setResult(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
hookAllMethods("com.android.server.am.ActivityManagerService", lpparam.classLoader, "appRestrictedInBackgroundLocked", hook);
|
|
||||||
hookAllMethods("com.android.server.am.ActivityManagerService", lpparam.classLoader, "appServicesRestrictedInBackgroundLocked", hook);
|
|
||||||
hookAllMethods("com.android.server.am.ActivityManagerService", lpparam.classLoader, "getAppStartModeLocked", hook);
|
|
||||||
}
|
|
||||||
} else if (lpparam.packageName.equals(APPLICATION_ID)) {
|
|
||||||
// Make sure Xposed work
|
|
||||||
XposedHelpers.findAndHookMethod(XposedApp.class.getName(), lpparam.classLoader, "isEnhancementEnabled", XC_MethodReplacement.returnConstant(true));
|
|
||||||
// XposedHelpers.findAndHookMethod(StatusInstallerFragment.class.getName(), lpparam.classLoader, "isSELinuxEnforced", XC_MethodReplacement.returnConstant(SELinuxHelper.isSELinuxEnforced()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -154,13 +154,6 @@
|
||||||
android:title="@string/pref_title_enable_boot_image_deopt"
|
android:title="@string/pref_title_enable_boot_image_deopt"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="disable_hidden_api_bypass"
|
|
||||||
android:summary="@string/settings_summary_disable_hidden_api_bypass"
|
|
||||||
android:title="@string/settings_title_disable_hidden_api_bypass"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
android:key="disable_resources"
|
android:key="disable_resources"
|
||||||
|
|
@ -188,32 +181,4 @@
|
||||||
android:title="@string/pref_title_disable_modules_log"
|
android:title="@string/pref_title_disable_modules_log"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:key="group_enhancement"
|
|
||||||
android:title="@string/settings_group_enhancement"
|
|
||||||
app:iconSpaceReserved="false">
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="enhancement_status"
|
|
||||||
android:summary="@string/settings_summary_enhancement"
|
|
||||||
android:title="@string/settings_title_enhancement"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="pretend_xposed_installer"
|
|
||||||
android:summary="@string/settings_summary_pretend_xposed_installer"
|
|
||||||
android:title="@string/settings_title_pretend_xposed_installer"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="hide_edxposed_manager"
|
|
||||||
android:summary="@string/settings_summary_hide_edxposed_manager"
|
|
||||||
android:title="@string/settings_title_hide_edxposed_manager"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
|
|
||||||
</PreferenceCategory>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
Loading…
Reference in New Issue