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<Long, Map<InetAddress, Boolean>> mapUidIPFilters = new HashMap<>();
|
||||||
private Map<Integer, Forward> mapForward = new HashMap<>();
|
private Map<Integer, Forward> mapForward = new HashMap<>();
|
||||||
|
|
||||||
private volatile Looper mServiceLooper;
|
private volatile Looper commandLooper;
|
||||||
private volatile ServiceHandler mServiceHandler;
|
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_ENFORCING = 1;
|
||||||
private static final int NOTIFY_WAITING = 2;
|
private static final int NOTIFY_WAITING = 2;
|
||||||
|
@ -165,21 +169,8 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
return wlInstance;
|
return wlInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class ServiceHandler extends Handler {
|
private final class CommandHandler extends Handler {
|
||||||
private boolean stats = false;
|
public CommandHandler(Looper looper) {
|
||||||
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) {
|
|
||||||
super(looper);
|
super(looper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,32 +181,13 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
case MSG_SERVICE_INTENT:
|
case MSG_SERVICE_INTENT:
|
||||||
handleIntent((Intent) msg.obj);
|
handleIntent((Intent) msg.obj);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
case MSG_STATS_START:
|
Log.e(TAG, "Unknown command message=" + msg.what);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
|
||||||
Util.sendCrashReport(ex, SinkholeService.this);
|
Util.sendCrashReport(ex, SinkholeService.this);
|
||||||
} finally {
|
} finally {
|
||||||
if (msg.what == MSG_SERVICE_INTENT)
|
|
||||||
try {
|
try {
|
||||||
PowerManager.WakeLock wl = getLock(SinkholeService.this);
|
PowerManager.WakeLock wl = getLock(SinkholeService.this);
|
||||||
if (wl.isHeld())
|
if (wl.isHeld())
|
||||||
|
@ -300,13 +272,16 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case stats:
|
case stats:
|
||||||
stopStats();
|
statsHandler.sendEmptyMessage(MSG_STATS_STOP);
|
||||||
startStats();
|
statsHandler.sendEmptyMessage(MSG_STATS_START);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case set:
|
case set:
|
||||||
set(intent);
|
set(intent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Log.e(TAG, "Unknown command=" + cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update main view
|
// 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() {
|
private void startStats() {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SinkholeService.this);
|
||||||
boolean enabled = (!stats && prefs.getBoolean("show_stats", false));
|
boolean enabled = (!stats && prefs.getBoolean("show_stats", false));
|
||||||
|
@ -474,7 +588,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
private void stopStats() {
|
private void stopStats() {
|
||||||
Log.i(TAG, "Stats stop");
|
Log.i(TAG, "Stats stop");
|
||||||
stats = false;
|
stats = false;
|
||||||
mServiceHandler.removeMessages(MSG_STATS_UPDATE);
|
this.removeMessages(MSG_STATS_UPDATE);
|
||||||
if (state == State.stats) {
|
if (state == State.stats) {
|
||||||
Log.d(TAG, "Stop foreground state=" + state.toString());
|
Log.d(TAG, "Stop foreground state=" + state.toString());
|
||||||
stopForeground(true);
|
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)));
|
int loglevel = Integer.parseInt(prefs.getString("loglevel", Integer.toString(Log.WARN)));
|
||||||
|
|
||||||
// Schedule next update
|
// Schedule next update
|
||||||
mServiceHandler.sendEmptyMessageDelayed(MSG_STATS_UPDATE, frequency);
|
this.sendEmptyMessageDelayed(MSG_STATS_UPDATE, frequency);
|
||||||
|
|
||||||
long ct = SystemClock.elapsedRealtime();
|
long ct = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
|
@ -678,74 +792,6 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
} else
|
} else
|
||||||
NotificationManagerCompat.from(SinkholeService.this).notify(NOTIFY_TRAFFIC, builder.build());
|
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) {
|
public static InetAddress getDns(Context context) {
|
||||||
|
@ -1120,18 +1166,18 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
|
|
||||||
// Called from native code
|
// Called from native code
|
||||||
private void logPacket(Packet packet) {
|
private void logPacket(Packet packet) {
|
||||||
Message msg = mServiceHandler.obtainMessage();
|
Message msg = logHandler.obtainMessage();
|
||||||
msg.obj = packet;
|
msg.obj = packet;
|
||||||
msg.what = MSG_PACKET;
|
msg.what = MSG_PACKET;
|
||||||
mServiceHandler.sendMessage(msg);
|
logHandler.sendMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from native code
|
// Called from native code
|
||||||
private void dnsResolved(ResourceRecord rr) {
|
private void dnsResolved(ResourceRecord rr) {
|
||||||
Message msg = mServiceHandler.obtainMessage();
|
Message msg = logHandler.obtainMessage();
|
||||||
msg.obj = rr;
|
msg.obj = rr;
|
||||||
msg.what = MSG_RR;
|
msg.what = MSG_RR;
|
||||||
mServiceHandler.sendMessage(msg);
|
logHandler.sendMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from native code
|
// Called from native code
|
||||||
|
@ -1227,7 +1273,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start/stop stats
|
// 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);
|
Util.setTheme(this);
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
HandlerThread thread = new HandlerThread(getString(R.string.app_name) + " handler");
|
HandlerThread commandThread = new HandlerThread(getString(R.string.app_name) + " command");
|
||||||
thread.start();
|
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();
|
commandLooper = commandThread.getLooper();
|
||||||
mServiceHandler = new ServiceHandler(mServiceLooper);
|
logLooper = logThread.getLooper();
|
||||||
|
statsLooper = statsThread.getLooper();
|
||||||
|
|
||||||
|
commandHandler = new CommandHandler(commandLooper);
|
||||||
|
logHandler = new LogHandler(logLooper);
|
||||||
|
statsHandler = new StatsHandler(statsLooper);
|
||||||
|
|
||||||
// Listen for interactive state changes
|
// Listen for interactive state changes
|
||||||
last_interactive = Util.isInteractive(this);
|
last_interactive = Util.isInteractive(this);
|
||||||
|
@ -1438,11 +1493,11 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
" vpn=" + (vpn != null) + " user=" + (Process.myUid() / 100000));
|
" vpn=" + (vpn != null) + " user=" + (Process.myUid() / 100000));
|
||||||
|
|
||||||
// Queue command
|
// Queue command
|
||||||
Message msg = mServiceHandler.obtainMessage();
|
Message msg = commandHandler.obtainMessage();
|
||||||
msg.arg1 = startId;
|
msg.arg1 = startId;
|
||||||
msg.obj = intent;
|
msg.obj = intent;
|
||||||
msg.what = MSG_SERVICE_INTENT;
|
msg.what = MSG_SERVICE_INTENT;
|
||||||
mServiceHandler.sendMessage(msg);
|
commandHandler.sendMessage(msg);
|
||||||
|
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
@ -1466,7 +1521,9 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
Log.i(TAG, "Destroy");
|
Log.i(TAG, "Destroy");
|
||||||
|
|
||||||
mServiceLooper.quit();
|
commandLooper.quit();
|
||||||
|
logLooper.quit();
|
||||||
|
statsLooper.quit();
|
||||||
|
|
||||||
unregisterReceiver(interactiveStateReceiver);
|
unregisterReceiver(interactiveStateReceiver);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
|
||||||
|
|
Loading…
Reference in New Issue