mirror of https://github.com/M66B/NetGuard.git
Separate command, log and stats handlers
This commit is contained in:
parent
2ab2ff00ec
commit
ebeae91ed3
|
@ -108,8 +108,12 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
private Map<Long, Map<InetAddress, Boolean>> mapUidIPFilters = new HashMap<>();
|
||||
private Map<Integer, Forward> mapForward = new HashMap<>();
|
||||
|
||||
private volatile Looper mServiceLooper;
|
||||
private volatile ServiceHandler mServiceHandler;
|
||||
private volatile Looper commandLooper;
|
||||
private volatile Looper logLooper;
|
||||
private volatile Looper statsLooper;
|
||||
private volatile CommandHandler commandHandler;
|
||||
private volatile LogHandler logHandler;
|
||||
private volatile StatsHandler statsHandler;
|
||||
|
||||
private static final int NOTIFY_ENFORCING = 1;
|
||||
private static final int NOTIFY_WAITING = 2;
|
||||
|
@ -165,21 +169,8 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
return wlInstance;
|
||||
}
|
||||
|
||||
private final class ServiceHandler extends Handler {
|
||||
private boolean stats = false;
|
||||
private long when;
|
||||
|
||||
private long t = -1;
|
||||
private long tx = -1;
|
||||
private long rx = -1;
|
||||
|
||||
private List<Long> gt = new ArrayList<>();
|
||||
private List<Float> gtx = new ArrayList<>();
|
||||
private List<Float> grx = new ArrayList<>();
|
||||
|
||||
private HashMap<Integer, Long> mapUidBytes = new HashMap<>();
|
||||
|
||||
public ServiceHandler(Looper looper) {
|
||||
private final class CommandHandler extends Handler {
|
||||
public CommandHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
|
@ -190,32 +181,13 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
case MSG_SERVICE_INTENT:
|
||||
handleIntent((Intent) msg.obj);
|
||||
break;
|
||||
|
||||
case MSG_STATS_START:
|
||||
startStats();
|
||||
break;
|
||||
|
||||
case MSG_STATS_STOP:
|
||||
stopStats();
|
||||
break;
|
||||
|
||||
case MSG_STATS_UPDATE:
|
||||
updateStats();
|
||||
break;
|
||||
|
||||
case MSG_PACKET:
|
||||
log((Packet) msg.obj);
|
||||
break;
|
||||
|
||||
case MSG_RR:
|
||||
resolved((ResourceRecord) msg.obj);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unknown command message=" + msg.what);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||
Util.sendCrashReport(ex, SinkholeService.this);
|
||||
} finally {
|
||||
if (msg.what == MSG_SERVICE_INTENT)
|
||||
try {
|
||||
PowerManager.WakeLock wl = getLock(SinkholeService.this);
|
||||
if (wl.isHeld())
|
||||
|
@ -300,13 +272,16 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
break;
|
||||
|
||||
case stats:
|
||||
stopStats();
|
||||
startStats();
|
||||
statsHandler.sendEmptyMessage(MSG_STATS_STOP);
|
||||
statsHandler.sendEmptyMessage(MSG_STATS_START);
|
||||
break;
|
||||
|
||||
case set:
|
||||
set(intent);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Unknown command=" + cmd);
|
||||
}
|
||||
|
||||
// Update main view
|
||||
|
@ -453,6 +428,145 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
}
|
||||
|
||||
private void set(Intent intent) {
|
||||
// Get arguments
|
||||
int uid = intent.getIntExtra(EXTRA_UID, 0);
|
||||
String network = intent.getStringExtra(EXTRA_NETWORK);
|
||||
String pkg = intent.getStringExtra(EXTRA_PACKAGE);
|
||||
boolean blocked = intent.getBooleanExtra(EXTRA_BLOCKED, false);
|
||||
Log.i(TAG, "Set " + pkg + " " + network + "=" + blocked);
|
||||
|
||||
// Get defaults
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
boolean default_wifi = settings.getBoolean("whitelist_wifi", true);
|
||||
boolean default_other = settings.getBoolean("whitelist_other", true);
|
||||
|
||||
// Update setting
|
||||
SharedPreferences prefs = getSharedPreferences(network, Context.MODE_PRIVATE);
|
||||
if (blocked == ("wifi".equals(network) ? default_wifi : default_other))
|
||||
prefs.edit().remove(pkg).apply();
|
||||
else
|
||||
prefs.edit().putBoolean(pkg, blocked).apply();
|
||||
|
||||
// Apply rules
|
||||
SinkholeService.reload(null, "notification", SinkholeService.this);
|
||||
|
||||
// Update notification
|
||||
Receiver.notifyNewApplication(uid, SinkholeService.this);
|
||||
|
||||
// Update UI
|
||||
Intent ruleset = new Intent(ActivityMain.ACTION_RULES_CHANGED);
|
||||
LocalBroadcastManager.getInstance(SinkholeService.this).sendBroadcast(ruleset);
|
||||
}
|
||||
}
|
||||
|
||||
private final class LogHandler extends Handler {
|
||||
public LogHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
try {
|
||||
switch (msg.what) {
|
||||
case MSG_PACKET:
|
||||
log((Packet) msg.obj);
|
||||
break;
|
||||
|
||||
case MSG_RR:
|
||||
resolved((ResourceRecord) msg.obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Unknown log message=" + msg.what);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||
Util.sendCrashReport(ex, SinkholeService.this);
|
||||
}
|
||||
}
|
||||
|
||||
private void log(Packet packet) {
|
||||
// Get settings
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
boolean log = prefs.getBoolean("log", false);
|
||||
boolean log_app = prefs.getBoolean("log_app", false);
|
||||
boolean notify = prefs.getBoolean("notify_access", false);
|
||||
boolean system = prefs.getBoolean("manage_system", false);
|
||||
|
||||
DatabaseHelper dh = DatabaseHelper.getInstance(SinkholeService.this);
|
||||
|
||||
// Get real name
|
||||
String dname = dh.getQName(packet.daddr);
|
||||
|
||||
// Traffic log
|
||||
if (log)
|
||||
dh.insertLog(packet, dname, (last_connected ? last_metered ? 2 : 1 : 0), last_interactive);
|
||||
|
||||
// Application log
|
||||
if (log_app && packet.uid >= 0) {
|
||||
if (!(packet.protocol == 6 /* TCP */ || packet.protocol == 17 /* UDP */))
|
||||
packet.dport = 0;
|
||||
if (dh.updateAccess(packet, dname, -1))
|
||||
if (notify && prefs.getBoolean("notify_" + packet.uid, true) &&
|
||||
(system || !Util.isSystem(packet.uid, SinkholeService.this)))
|
||||
showAccessNotification(packet.uid);
|
||||
}
|
||||
|
||||
if (packet.uid < 0 && packet.dport != 53)
|
||||
Log.w(TAG, "Unknown application packet " + packet);
|
||||
}
|
||||
|
||||
private void resolved(ResourceRecord rr) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
if (prefs.getBoolean("resolved", true))
|
||||
DatabaseHelper.getInstance(SinkholeService.this).insertDns(rr);
|
||||
}
|
||||
}
|
||||
|
||||
private final class StatsHandler extends Handler {
|
||||
private boolean stats = false;
|
||||
private long when;
|
||||
|
||||
private long t = -1;
|
||||
private long tx = -1;
|
||||
private long rx = -1;
|
||||
|
||||
private List<Long> gt = new ArrayList<>();
|
||||
private List<Float> gtx = new ArrayList<>();
|
||||
private List<Float> grx = new ArrayList<>();
|
||||
|
||||
private HashMap<Integer, Long> mapUidBytes = new HashMap<>();
|
||||
|
||||
public StatsHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
try {
|
||||
switch (msg.what) {
|
||||
case MSG_STATS_START:
|
||||
startStats();
|
||||
break;
|
||||
|
||||
case MSG_STATS_STOP:
|
||||
stopStats();
|
||||
break;
|
||||
|
||||
case MSG_STATS_UPDATE:
|
||||
updateStats();
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Unknown stats message=" + msg.what);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||
Util.sendCrashReport(ex, SinkholeService.this);
|
||||
}
|
||||
}
|
||||
|
||||
private void startStats() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
boolean enabled = (!stats && prefs.getBoolean("show_stats", false));
|
||||
|
@ -474,7 +588,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
private void stopStats() {
|
||||
Log.i(TAG, "Stats stop");
|
||||
stats = false;
|
||||
mServiceHandler.removeMessages(MSG_STATS_UPDATE);
|
||||
this.removeMessages(MSG_STATS_UPDATE);
|
||||
if (state == State.stats) {
|
||||
Log.d(TAG, "Stop foreground state=" + state.toString());
|
||||
stopForeground(true);
|
||||
|
@ -494,7 +608,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
int loglevel = Integer.parseInt(prefs.getString("loglevel", Integer.toString(Log.WARN)));
|
||||
|
||||
// Schedule next update
|
||||
mServiceHandler.sendEmptyMessageDelayed(MSG_STATS_UPDATE, frequency);
|
||||
this.sendEmptyMessageDelayed(MSG_STATS_UPDATE, frequency);
|
||||
|
||||
long ct = SystemClock.elapsedRealtime();
|
||||
|
||||
|
@ -678,74 +792,6 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
} else
|
||||
NotificationManagerCompat.from(SinkholeService.this).notify(NOTIFY_TRAFFIC, builder.build());
|
||||
}
|
||||
|
||||
private void log(Packet packet) {
|
||||
// Get settings
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
boolean log = prefs.getBoolean("log", false);
|
||||
boolean log_app = prefs.getBoolean("log_app", false);
|
||||
boolean notify = prefs.getBoolean("notify_access", false);
|
||||
boolean system = prefs.getBoolean("manage_system", false);
|
||||
|
||||
DatabaseHelper dh = DatabaseHelper.getInstance(SinkholeService.this);
|
||||
|
||||
// Get real name
|
||||
String dname = dh.getQName(packet.daddr);
|
||||
|
||||
// Traffic log
|
||||
if (log)
|
||||
dh.insertLog(packet, dname, (last_connected ? last_metered ? 2 : 1 : 0), last_interactive);
|
||||
|
||||
// Application log
|
||||
if (log_app && packet.uid >= 0) {
|
||||
if (!(packet.protocol == 6 /* TCP */ || packet.protocol == 17 /* UDP */))
|
||||
packet.dport = 0;
|
||||
if (dh.updateAccess(packet, dname, -1))
|
||||
if (notify && prefs.getBoolean("notify_" + packet.uid, true) &&
|
||||
(system || !Util.isSystem(packet.uid, SinkholeService.this)))
|
||||
showAccessNotification(packet.uid);
|
||||
}
|
||||
|
||||
if (packet.uid < 0 && packet.dport != 53)
|
||||
Log.w(TAG, "Unknown application packet " + packet);
|
||||
}
|
||||
|
||||
private void resolved(ResourceRecord rr) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
if (prefs.getBoolean("resolved", true))
|
||||
DatabaseHelper.getInstance(SinkholeService.this).insertDns(rr);
|
||||
}
|
||||
|
||||
private void set(Intent intent) {
|
||||
// Get arguments
|
||||
int uid = intent.getIntExtra(EXTRA_UID, 0);
|
||||
String network = intent.getStringExtra(EXTRA_NETWORK);
|
||||
String pkg = intent.getStringExtra(EXTRA_PACKAGE);
|
||||
boolean blocked = intent.getBooleanExtra(EXTRA_BLOCKED, false);
|
||||
Log.i(TAG, "Set " + pkg + " " + network + "=" + blocked);
|
||||
|
||||
// Get defaults
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||
boolean default_wifi = settings.getBoolean("whitelist_wifi", true);
|
||||
boolean default_other = settings.getBoolean("whitelist_other", true);
|
||||
|
||||
// Update setting
|
||||
SharedPreferences prefs = getSharedPreferences(network, Context.MODE_PRIVATE);
|
||||
if (blocked == ("wifi".equals(network) ? default_wifi : default_other))
|
||||
prefs.edit().remove(pkg).apply();
|
||||
else
|
||||
prefs.edit().putBoolean(pkg, blocked).apply();
|
||||
|
||||
// Apply rules
|
||||
SinkholeService.reload(null, "notification", SinkholeService.this);
|
||||
|
||||
// Update notification
|
||||
Receiver.notifyNewApplication(uid, SinkholeService.this);
|
||||
|
||||
// Update UI
|
||||
Intent ruleset = new Intent(ActivityMain.ACTION_RULES_CHANGED);
|
||||
LocalBroadcastManager.getInstance(SinkholeService.this).sendBroadcast(ruleset);
|
||||
}
|
||||
}
|
||||
|
||||
public static InetAddress getDns(Context context) {
|
||||
|
@ -1120,18 +1166,18 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
|
||||
// Called from native code
|
||||
private void logPacket(Packet packet) {
|
||||
Message msg = mServiceHandler.obtainMessage();
|
||||
Message msg = logHandler.obtainMessage();
|
||||
msg.obj = packet;
|
||||
msg.what = MSG_PACKET;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
logHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
// Called from native code
|
||||
private void dnsResolved(ResourceRecord rr) {
|
||||
Message msg = mServiceHandler.obtainMessage();
|
||||
Message msg = logHandler.obtainMessage();
|
||||
msg.obj = rr;
|
||||
msg.what = MSG_RR;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
logHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
// Called from native code
|
||||
|
@ -1227,7 +1273,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
}
|
||||
|
||||
// Start/stop stats
|
||||
mServiceHandler.sendEmptyMessage(Util.isInteractive(SinkholeService.this) ? MSG_STATS_START : MSG_STATS_STOP);
|
||||
statsHandler.sendEmptyMessage(Util.isInteractive(SinkholeService.this) ? MSG_STATS_START : MSG_STATS_STOP);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1356,11 +1402,20 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
Util.setTheme(this);
|
||||
super.onCreate();
|
||||
|
||||
HandlerThread thread = new HandlerThread(getString(R.string.app_name) + " handler");
|
||||
thread.start();
|
||||
HandlerThread commandThread = new HandlerThread(getString(R.string.app_name) + " command");
|
||||
HandlerThread logThread = new HandlerThread(getString(R.string.app_name) + " log");
|
||||
HandlerThread statsThread = new HandlerThread(getString(R.string.app_name) + " stats");
|
||||
commandThread.start();
|
||||
logThread.start();
|
||||
statsThread.start();
|
||||
|
||||
mServiceLooper = thread.getLooper();
|
||||
mServiceHandler = new ServiceHandler(mServiceLooper);
|
||||
commandLooper = commandThread.getLooper();
|
||||
logLooper = logThread.getLooper();
|
||||
statsLooper = statsThread.getLooper();
|
||||
|
||||
commandHandler = new CommandHandler(commandLooper);
|
||||
logHandler = new LogHandler(logLooper);
|
||||
statsHandler = new StatsHandler(statsLooper);
|
||||
|
||||
// Listen for interactive state changes
|
||||
last_interactive = Util.isInteractive(this);
|
||||
|
@ -1438,11 +1493,11 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
" vpn=" + (vpn != null) + " user=" + (Process.myUid() / 100000));
|
||||
|
||||
// Queue command
|
||||
Message msg = mServiceHandler.obtainMessage();
|
||||
Message msg = commandHandler.obtainMessage();
|
||||
msg.arg1 = startId;
|
||||
msg.obj = intent;
|
||||
msg.what = MSG_SERVICE_INTENT;
|
||||
mServiceHandler.sendMessage(msg);
|
||||
commandHandler.sendMessage(msg);
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
@ -1466,7 +1521,9 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
|||
public void onDestroy() {
|
||||
Log.i(TAG, "Destroy");
|
||||
|
||||
mServiceLooper.quit();
|
||||
commandLooper.quit();
|
||||
logLooper.quit();
|
||||
statsLooper.quit();
|
||||
|
||||
unregisterReceiver(interactiveStateReceiver);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||
|
|
Loading…
Reference in New Issue