diff --git a/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java b/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java index 8a0670ad..ae1ca369 100644 --- a/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java +++ b/app/src/main/java/eu/faircode/netguard/ServiceSinkhole.java @@ -122,8 +122,6 @@ import java.util.Objects; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.zip.GZIPInputStream; @@ -216,7 +214,7 @@ public enum Command { private static volatile PowerManager.WakeLock wlInstance = null; - private ExecutorService executor = Executors.newCachedThreadPool(); + // executor removed: was only used by old interactiveStateReceiver reload logic private static final String ACTION_HOUSE_HOLDING = "eu.faircode.netguard.HOUSE_HOLDING"; private static final String ACTION_SCREEN_OFF_DELAYED = "eu.faircode.netguard.SCREEN_OFF_DELAYED"; @@ -559,23 +557,6 @@ private void start() { private void reload(boolean interactive) { List listRule = Rule.getRules(true, ServiceSinkhole.this); - // Check if rules needs to be reloaded - if (interactive) { - boolean process = false; - for (Rule rule : listRule) { - boolean blocked = (last_metered ? rule.other_blocked : rule.wifi_blocked); - boolean screen = (last_metered ? rule.screen_other : rule.screen_wifi); - if (blocked && screen) { - process = true; - break; - } - } - if (!process) { - Log.i(TAG, "No changed rules on interactive state change"); - return; - } - } - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSinkhole.this); // Refresh cached preferences for shouldTrackApp() @@ -1965,69 +1946,25 @@ private void prepareForwarding() { } private List getAllowedRules(List listRule) { - List listAllowed = new ArrayList<>(); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - // Check state - boolean wifi = Util.isWifiActive(this); - boolean metered = Util.isMeteredNetwork(this); - boolean useMetered = prefs.getBoolean("use_metered", false); - String ssidNetwork = Util.getWifiSSID(this); - String generation = Util.getNetworkGeneration(this); - boolean unmetered_2g = prefs.getBoolean("unmetered_2g", false); - boolean unmetered_3g = prefs.getBoolean("unmetered_3g", false); - boolean unmetered_4g = prefs.getBoolean("unmetered_4g", false); - boolean roaming = Util.isRoaming(ServiceSinkhole.this); - boolean national = prefs.getBoolean("national_roaming", false); - boolean eu = prefs.getBoolean("eu_roaming", false); - boolean tethering = prefs.getBoolean("tethering", false); - boolean filter = prefs.getBoolean("filter", true); - - // Update connected state + // TrackerControl: In filter mode (always on for TC), the allowed rules list + // doesn't affect VPN routing or tracker blocking. The VPN builder uses rule.apply + // (network-independent) and tracker blocking is handled dynamically in + // blockKnownTracker(). We just return all rules for the notification count. last_connected = Util.isConnected(ServiceSinkhole.this); - boolean org_metered = metered; - boolean org_roaming = roaming; - - // Update metered state - if (wifi && !useMetered) - metered = false; - if (unmetered_2g && "2G".equals(generation)) - metered = false; - if (unmetered_3g && "3G".equals(generation)) - metered = false; - if (unmetered_4g && "4G".equals(generation)) + // Preserve metered override: treat WiFi as unmetered unless use_metered is set. + // This affects isLockedDown() which is still used for IP filter rules. + boolean metered = Util.isMeteredNetwork(this); + if (Util.isWifiActive(this) && + !PreferenceManager.getDefaultSharedPreferences(this).getBoolean("use_metered", false)) metered = false; last_metered = metered; - // Update roaming state - if (roaming && eu) - roaming = !Util.isEU(this); - if (roaming && national) - roaming = !Util.isNational(this); - - Log.i(TAG, "Get allowed" + - " connected=" + last_connected + - " wifi=" + wifi + - " network=" + ssidNetwork + - " metered=" + metered + "/" + org_metered + - " generation=" + generation + - " roaming=" + roaming + "/" + org_roaming + - " interactive=" + last_interactive + - " tethering=" + tethering + - " filter=" + filter); + Log.i(TAG, "Get allowed connected=" + last_connected + + " metered=" + last_metered + + " rules=" + listRule.size()); - if (last_connected) - for (Rule rule : listRule) { - boolean blocked = (metered ? rule.other_blocked : rule.wifi_blocked); - boolean screen = (metered ? rule.screen_other : rule.screen_wifi); - if ((!blocked || (screen && last_interactive)) && - (!metered || !(rule.roaming && roaming))) - listAllowed.add(rule); - } - - Log.i(TAG, "Allowed " + listAllowed.size() + " of " + listRule.size()); - return listAllowed; + return new ArrayList<>(listRule); } private void stopVPN(ParcelFileDescriptor pfd) { @@ -2378,33 +2315,14 @@ public void onReceive(final Context context, final Intent intent) { Log.i(TAG, "Received " + intent); Util.logExtras(intent); - executor.submit(new Runnable() { - @Override - public void run() { - AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - Intent i = new Intent(ACTION_SCREEN_OFF_DELAYED); - i.setPackage(context.getPackageName()); - PendingIntent pi = PendingIntentCompat.getBroadcast(context, 0, i, - PendingIntent.FLAG_UPDATE_CURRENT); - am.cancel(pi); - - try { - last_interactive = Intent.ACTION_SCREEN_ON.equals(intent.getAction()); - reload("interactive state changed", ServiceSinkhole.this, true); - - // Start/stop stats - statsHandler.sendEmptyMessage( - Util.isInteractive(ServiceSinkhole.this) ? MSG_STATS_START : MSG_STATS_STOP); - } catch (Throwable ex) { - Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex)); + // TrackerControl: skip VPN rebuild on screen on/off. + // TC doesn't use screen-based per-network blocking rules (screen_wifi/screen_other). + // Just update the interactive state for stats handling. + last_interactive = Intent.ACTION_SCREEN_ON.equals(intent.getAction()); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) - am.set(AlarmManager.RTC_WAKEUP, new Date().getTime() + 15 * 1000L, pi); - else - am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, new Date().getTime() + 15 * 1000L, pi); - } - } - }); + // Start/stop stats + statsHandler.sendEmptyMessage( + Util.isInteractive(ServiceSinkhole.this) ? MSG_STATS_START : MSG_STATS_STOP); } }; @@ -2445,6 +2363,8 @@ public void onReceive(Context context, Intent intent) { Log.i(TAG, "device idle=" + pm.isDeviceIdleMode()); // Reload rules when coming from idle mode + // This ensures the native tunnel thread is healthy after Doze + // network restrictions are lifted if (!pm.isDeviceIdleMode()) reload("idle state changed", ServiceSinkhole.this, false); } @@ -2454,9 +2374,10 @@ public void onReceive(Context context, Intent intent) { @Override @TargetApi(Build.VERSION_CODES.M) public void onReceive(Context context, Intent intent) { - Log.i(TAG, "Received " + intent); + // TrackerControl: skip VPN rebuild on hotspot state changes. + // TC's tracker blocking is independent of tethering/AP state. + Log.i(TAG, "AP state changed (skipping reload): " + intent); Util.logExtras(intent); - reload("AP state changed", ServiceSinkhole.this, false); } }; @@ -2471,10 +2392,12 @@ public void onReceive(Context context, Intent intent) { return; } - // Reload rules - Log.i(TAG, "Received " + intent); + // TrackerControl: skip VPN rebuild on network changes. + // Unlike NetGuard, TC doesn't apply different blocking rules per network type + // (WiFi vs mobile). Tracker blocking is handled dynamically in blockKnownTracker() + // and the VPN app routing (filter mode) is network-independent. + Log.i(TAG, "Connectivity changed (skipping reload): " + intent); Util.logExtras(intent); - reload("connectivity changed", ServiceSinkhole.this, false); } }; @@ -2581,17 +2504,11 @@ private void checkConnectivity(Network network, NetworkInfo ni, NetworkCapabilit public void onDataConnectionStateChanged(int state, int networkType) { if (state == TelephonyManager.DATA_CONNECTED) { String current_generation = Util.getNetworkGeneration(ServiceSinkhole.this); - Log.i(TAG, "Data connected generation=" + current_generation); - + // TrackerControl: skip VPN rebuild on network generation changes. + // TC doesn't differentiate blocking by 2G/3G/4G network type. if (last_generation == null || !last_generation.equals(current_generation)) { - Log.i(TAG, "New network generation=" + current_generation); + Log.i(TAG, "Network generation changed to " + current_generation + " (skipping reload)"); last_generation = current_generation; - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSinkhole.this); - if (prefs.getBoolean("unmetered_2g", false) || - prefs.getBoolean("unmetered_3g", false) || - prefs.getBoolean("unmetered_4g", false)) - reload("data connection state changed", ServiceSinkhole.this, false); } } } @@ -3239,7 +3156,7 @@ public void onDestroy() { } } - executor.shutdownNow(); + // executor.shutdownNow() removed: executor no longer used super.onDestroy(); }