### Configure Xposed Module Metadata and Scope in AndroidManifest.xml Source: https://context7.com/canyie/settingsfirewall/llms.txt This XML snippet configures an Android application as an Xposed module. It includes essential metadata such as module status, description, minimum Xposed version, and the scope of hooks. It also requests the necessary permission to query all installed packages. ```xml ``` -------------------------------- ### Manage Firewall Targets in Main Activity - Java Source: https://context7.com/canyie/settingsfirewall/llms.txt This Java code snippet demonstrates the MainActivity for the Settings Firewall project. It handles the initialization of the firewall service, loading and displaying a list of applications, and managing user interactions such as toggling firewall targets and navigating to an editor for individual app settings. Dependencies include Android Activity, View, Bundle, Intent, and the custom ISettingsFirewall service. ```java public class MainActivity extends Activity { private ISettingsFirewall service; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); service = App.getService(this); if (service == null) { // Module not activated findViewById(R.id.not_activated_msg).setVisibility(View.VISIBLE); return; } // Load and display app list ListView listView = findViewById(R.id.list); AppListAdapter adapter = new AppListAdapter(this, App.getSortedList(this, service)); listView.setAdapter(adapter); } // Handle checkbox toggle public void onItemChecked(AppInfo appInfo, boolean checked) { try { appInfo.enabled = checked; service.setTarget(appInfo.uid, checked); } catch (RemoteException e) { throw new RuntimeException(e); } } // Handle item click to edit replacements public void onItemClicked(AppInfo appInfo) { startActivity(new Intent(this, SettingsEditActivity.class) .putExtra(SettingsEditActivity.KEY_UID, appInfo.uid) .putExtra(SettingsEditActivity.KEY_NAME, appInfo.name)); } } ``` -------------------------------- ### Discover Android System Settings using Java Reflection Source: https://context7.com/canyie/settingsfirewall/llms.txt This Java code dynamically discovers all available Android settings (System, Secure, Global) by inspecting their respective classes using reflection. It identifies settings, handles moved settings, and checks for existing replacements. Dependencies include Android SDK classes like Settings, TextUtils, and reflection APIs. ```java // App.java - Settings discovery public static List getSettings(ISettingsFirewall service, int uid) { Replacement[] replacements; try { replacements = service.getReplacements(uid); } catch (RemoteException e) { throw new RuntimeException(e); } List out = new ArrayList<>(); // Add all Settings.System fields addSettings(Settings.System.class, out, Replacement.FLAG_SYSTEM, replacements, "MOVED_TO_SECURE", "MOVED_TO_GLOBAL", "MOVED_TO_SECURE_THEN_GLOBAL"); // Add all Settings.Secure fields addSettings(Settings.Secure.class, out, Replacement.FLAG_SECURE, replacements, "MOVED_TO_GLOBAL"); // Add all Settings.Global fields addSettings(Settings.Global.class, out, Replacement.FLAG_GLOBAL, replacements); Collections.sort(out, Replacement.COMPARATOR); return out; } private static void addSettings(Class cls, List out, int flag, Replacement[] replacements, String... ignore) { // Load ignore sets (settings that moved to other namespaces) Set[] ignoreSets = new Set[ignore.length]; for (int i = 0; i < ignore.length; i++) { try { Field field = cls.getDeclaredField(ignore[i]); field.setAccessible(true); ignoreSets[i] = (Set) field.get(null); } catch (Exception e) { ignoreSets[i] = Collections.emptySet(); } } // Iterate all static final String fields Field[] fields = cls.getDeclaredFields(); for (Field field : fields) { int modifiers = field.getModifiers(); if (!(Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers))) continue; if (field.getType() != String.class) continue; field.setAccessible(true); String key; try { key = (String) field.get(null); } catch (Exception e) { continue; } if (TextUtils.isEmpty(key)) continue; // Skip ignored settings boolean skip = false; for (Set set : ignoreSets) { if (set.contains(key)) { skip = true; break; } } if (skip) continue; // Check if we already have a replacement for this setting if (replacements != null) { for (Replacement existing : replacements) { if (key.equals(existing.key)) { out.add(existing); continue; } } } // Add as unreplaced setting (value = null) out.add(new Replacement(key, null, flag)); } } ``` -------------------------------- ### Android App Build Configuration (Gradle) Source: https://context7.com/canyie/settingsfirewall/llms.txt Configures the Android application build process, including SDK versions, build features like AIDL and BuildConfig, and dependency management for Xposed API and hidden API bypass. ```gradle // app/build.gradle plugins { id 'com.android.application' } android { namespace 'top.canyie.settingsfirewall' compileSdk 34 defaultConfig { applicationId "top.canyie.settingsfirewall" minSdk 18 // Android 4.3+ targetSdk 34 versionCode 1 versionName "1.0" } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } buildFeatures { aidl true // Enable AIDL compilation buildConfig true } } dependencies { // Xposed API (compile-only, provided by framework at runtime) compileOnly 'de.robv.android.xposed:api:82' // Hidden API access for Android P+ (reflection restrictions bypass) implementation 'org.lsposed.hiddenapibypass:hiddenapibypass:4.3' } ``` -------------------------------- ### Connect to Firewall Service (Java) Source: https://context7.com/canyie/settingsfirewall/llms.txt Demonstrates how to connect to the ISettingsFirewall service from the application UI using Android's ContentResolver. It handles service discovery and retrieves the service binder. ```java // App.java - Service discovery public class App extends Application { private static ISettingsFirewall service; public static ISettingsFirewall getService(Context context) { if (service == null) { // Call Settings Provider with our custom method to get the service binder Uri uri = Uri.parse("content://" + Settings.AUTHORITY); try { Bundle result = context.getContentResolver().call( uri, SettingsProviderHook.METHOD, // "GET_SettingsFirewall" null, null ); if (result != null) { service = ISettingsFirewall.Stub.asInterface( result.getBinder(Settings.NameValueTable.VALUE) ); } } catch (Exception ignored) { // Service not available - module not activated } } return service; } // Load installed apps with firewall status public static List getSortedList(Context context, ISettingsFirewall service) { PackageManager pm = context.getPackageManager(); var apps = pm.getInstalledPackages(0); int[] enabledUids; try { enabledUids = service.getTargets(); } catch (RemoteException e) { throw new RuntimeException(e); } Arrays.sort(enabledUids); List list = new ArrayList<>(); for (var app : apps) { int uid = app.applicationInfo.uid; if (uid < Process.SHELL_UID || uid == Process.myUid()) continue; AppInfo info = new AppInfo(); info.name = app.applicationInfo.loadLabel(pm).toString(); info.icon = app.applicationInfo.loadIcon(pm); info.uid = uid; info.enabled = Arrays.binarySearch(enabledUids, uid) >= 0; list.add(info); } Collections.sort(list, AppInfo.COMPARATOR); return list; } } ``` -------------------------------- ### Implement Replacement Data Model (Java) Source: https://context7.com/canyie/settingsfirewall/llms.txt Implements the Parcelable data class for a setting replacement rule. It includes flags for different settings namespaces and methods for IPC serialization. ```java // Replacement.java public final class Replacement implements Serializable, Parcelable { public static final int FLAG_SYSTEM = 1 << 0; // Settings.System namespace public static final int FLAG_SECURE = 1 << 1; // Settings.Secure namespace public static final int FLAG_GLOBAL = 1 << 2; // Settings.Global namespace public final String key; // Setting name (e.g., "adb_enabled") public String value; // Replacement value (null = not replaced) public int flags; // Bitfield of FLAG_* constants public Replacement(String name, String value, int flags) { this.key = name; this.value = value; this.flags = flags; } // Parcelable implementation for IPC @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(key); dest.writeString(value); dest.writeInt(this.flags); } public static final Creator CREATOR = new Creator<>() { @Override public Replacement createFromParcel(Parcel in) { return new Replacement(in.readString(), in.readString(), in.readInt()); } @Override public Replacement[] newArray(int size) { return new Replacement[size]; } }; } ``` -------------------------------- ### Define IPC Service Interface (AIDL) Source: https://context7.com/canyie/settingsfirewall/llms.txt Defines the AIDL interface for cross-process communication between the UI and the system service. It includes methods for managing firewall targets and replacement rules. ```aidl // ISettingsFirewall.aidl package top.canyie.settingsfirewall; import top.canyie.settingsfirewall.Replacement; interface ISettingsFirewall { // Get all UIDs with firewall enabled int[] getTargets() = 1; // Enable/disable firewall for specific UID void setTarget(int uid, boolean enabled) = 2; // Get all replacement rules for a UID Replacement[] getReplacements(int uid) = 3; // Set replacement value for a specific setting void setReplacement(int uid, String setting, String value, int flags) = 4; // Remove replacement rule void deleteReplacement(int uid, String setting) = 5; } ``` -------------------------------- ### Java Firewall Policy Management Service Source: https://context7.com/canyie/settingsfirewall/llms.txt Implements an IPC service for managing firewall policies. It supports thread-safe operations for loading, retrieving, and setting firewall rules. Dependencies include Android Context, SharedPreferences, File I/O, and Xposed Bridge for logging. ```java // SettingsFirewallService.java - IPC service for policy management public class SettingsFirewallService extends ISettingsFirewall.Stub { public static final SettingsFirewallService INSTANCE = new SettingsFirewallService(); private static final Set targetUids = new HashSet<>(); private static final SparseArray> policyCache = new SparseArray<>(); private static final Lock readLock, writeLock; static { var lock = new ReentrantReadWriteLock(); readLock = lock.readLock(); writeLock = lock.writeLock(); } public static void init(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) context = context.createDeviceProtectedStorageContext(); // Load target UIDs from SharedPreferences sharedPreferences = context.getSharedPreferences("settings-firewall", Context.MODE_PRIVATE); var uidSet = sharedPreferences.getStringSet("firewall_targets", null); if (uidSet != null) { for (String uid : uidSet) { targetUids.add(Integer.valueOf(uid)); } } // Load replacement policies from serialized files policyDir = context.getDir("settings-firewall", Context.MODE_PRIVATE); File[] files = policyDir.listFiles(); for (File file : files) { int uid = Integer.parseInt(file.getName()); try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(file))) { policyCache.put(uid, (List) in.readObject()); } catch (Exception e) { XposedBridge.log("Error reading " + file); } } } // Thread-safe lookup of replacement values public static String getReplacement(int uid, String setting, int flag) { readLock.lock(); try { if (!targetUids.contains(uid)) return null; List replacements = policyCache.get(uid); if (replacements != null) { for (Replacement replacement : replacements) { if (setting.equals(replacement.key) && (replacement.flags & flag) != 0) { return replacement.value; } } } } finally { readLock.unlock(); } return null; } // Enable/disable firewall for specific UID @Override public void setTarget(int uid, boolean enabled) { writeLock.lock(); try { if (enabled) targetUids.add(uid); else targetUids.remove(uid); // Persist to SharedPreferences Set stringSet = new HashSet<>(); for (Integer u : targetUids) { stringSet.add(u.toString()); } sharedPreferences.edit().putStringSet("firewall_targets", stringSet).commit(); } finally { writeLock.unlock(); } } // Add or update replacement rule @Override public void setReplacement(int uid, String setting, String value, int flags) { writeLock.lock(); try { List replacements = policyCache.get(uid); if (replacements == null) { policyCache.put(uid, replacements = new ArrayList<>()); } // Update existing or add new boolean found = false; for (Replacement replacement : replacements) { if (setting.equals(replacement.key)) { replacement.value = value; replacement.flags = flags; found = true; break; } } if (!found) { replacements.add(new Replacement(setting, value, flags)); } // Persist to file try (ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream(new File(policyDir, Integer.toString(uid))))) { out.writeObject(replacements); } catch (IOException e) { XposedBridge.log("Error saving rules of uid " + uid); } } finally { writeLock.unlock(); } } } ``` -------------------------------- ### Hook Scope Configuration (XML) Source: https://context7.com/canyie/settingsfirewall/llms.txt Defines the scope of hooks for the firewall module, specifying system components like the Android framework and Settings Provider that the module will intercept. ```xml android com.android.providers.settings ``` -------------------------------- ### Intercept Settings Access with Xposed Source: https://context7.com/canyie/settingsfirewall/llms.txt This Java code implements the core Xposed hook for the SettingsFirewall module. It intercepts calls to the `SettingsProvider.call()` method to monitor and control application access to system settings. It requires the Xposed framework and operates on Android 4.3+. ```java // SettingsProviderHook.java - Main Xposed hook implementation public class SettingsProviderHook extends XC_MethodHook implements IXposedHookLoadPackage { public static final String METHOD = "GET_SettingsFirewall"; @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { if (!"com.android.providers.settings".equals(lpparam.packageName)) return; // Hook the SettingsProvider.call() method XposedHelpers.findAndHookMethod( "com.android.providers.settings.SettingsProvider", lpparam.classLoader, "call", String.class, // method parameter String.class, // name parameter Bundle.class, // args parameter this ); } @Override protected void beforeHookedMethod(MethodHookParam param) { ContentProvider contentProvider = (ContentProvider) param.thisObject; String method = (String) param.args[0]; String name = (String) param.args[1]; int callingUid = Binder.getCallingUid(); // Handle service discovery from our own app if (METHOD.equals(method)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !BuildConfig.APPLICATION_ID.equals(contentProvider.getCallingPackage())) { return; } param.setResult(SettingsFirewallService.BUNDLE); return; } // Intercept GET operations int flag; switch (method) { case "GET_global": flag = Replacement.FLAG_GLOBAL; break; case "GET_secure": flag = Replacement.FLAG_SECURE; break; case "GET_system": flag = Replacement.FLAG_SYSTEM; break; default: return; } // Check if we have a replacement value for this UID and setting String replacement = SettingsFirewallService.getReplacement(callingUid, name, flag); if (replacement != null) { Bundle result = new Bundle(1); result.putString(Settings.NameValueTable.VALUE, replacement); param.setResult(result); // Return fake value instead of real setting } } } ``` -------------------------------- ### Edit App Settings Replacement Values - Java Source: https://context7.com/canyie/settingsfirewall/llms.txt This Java code snippet details the SettingsEditActivity, responsible for editing individual setting replacement values for a given application. It initializes the service, loads existing settings, and provides UI elements for users to modify or delete replacement values. The activity uses Android AlertDialog for editing and interacts with the ISettingsFirewall service to persist changes. Dependencies include Android Activity, View, AlertDialog, EditText, and the custom ISettingsFirewall service. ```java public class SettingsEditActivity extends Activity { private int uid; private ISettingsFirewall service; private SettingListAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); uid = getIntent().getIntExtra(KEY_UID, -1); service = App.getService(this); // Load all available settings with current replacement values List settings = App.getSettings(service, uid); adapter = new SettingListAdapter(this, settings); ListView listView = findViewById(R.id.list); listView.setAdapter(adapter); } public void onItemClicked(Replacement replacement) { var layout = layoutInflater.inflate(R.layout.edit_dialog, null); EditText editText = layout.findViewById(R.id.edit); if (replacement.value != null) editText.setText(replacement.value); new AlertDialog.Builder(this) .setTitle(getString(R.string.editing, replacement.key)) .setView(layout) .setPositiveButton(R.string.save, (dialog, which) -> { // Save replacement value replacement.value = editText.getText().toString(); try { service.setReplacement(uid, replacement.key, replacement.value, replacement.flags); } catch (RemoteException e) { throw new RuntimeException(e); } adapter.notifyDataSetChanged(); }) .setNeutralButton(R.string.delete, (dialog, which) -> { // Remove replacement (allow real value through) replacement.value = null; try { service.deleteReplacement(uid, replacement.key); } catch (RemoteException e) { throw new RuntimeException(e); } adapter.notifyDataSetChanged(); }) .show(); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.