Add ability to start at boot

Closes #100
This commit is contained in:
emanuele-f 2021-11-06 19:30:43 +01:00
parent 85f2333e5b
commit 8399e30fab
8 changed files with 99 additions and 9 deletions

View File

@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_CLIPS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
@ -95,6 +96,15 @@
<meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
android:value="false"/>
</service>
<receiver
android:name=".BootReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
</application>
</manifest>

View File

@ -0,0 +1,67 @@
/*
* This file is part of PCAPdroid.
*
* PCAPdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PCAPdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PCAPdroid. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2020-21 - Emanuele Faranda
*/
package com.emanuelef.remote_capture;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.util.Log;
import androidx.core.content.ContextCompat;
import androidx.preference.PreferenceManager;
import com.emanuelef.remote_capture.model.CaptureSettings;
import com.emanuelef.remote_capture.model.Prefs;
public class BootReceiver extends BroadcastReceiver {
private static final String TAG = "BootReceiver";
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String action = intent.getAction();
Log.d(TAG, "onReceive: " + action);
if(!action.equals(Intent.ACTION_BOOT_COMPLETED) && !action.equals("android.intent.action.QUICKBOOT_POWERON")) {
Log.w(TAG, "Unexpected action: " + action);
return;
}
if(Prefs.startAtBoot(prefs)) {
CaptureSettings settings = new CaptureSettings(prefs);
if(!settings.root_capture) {
Intent vpnPrepareIntent = VpnService.prepare(context);
if(vpnPrepareIntent != null) {
// Cannot perform the VPN setup without an Activity
Utils.showToastLong(context, R.string.vpn_setup_failed);
return;
}
}
Log.i(TAG, "Starting capture service");
Intent capIntent = new Intent(context, CaptureService.class);
capIntent.putExtra("settings", settings);
ContextCompat.startForegroundService(context, capIntent);
}
}
}

View File

@ -65,13 +65,12 @@ public class Geolocation {
InputStream is = mContext.getResources().openRawResource(R.raw.dbip_country_lite_2021_11_mmdb_gz);
GZIPInputStream gis = new GZIPInputStream(is);
mCountryReader = new Reader(gis, cache);
Metadata meta = mCountryReader.getMetadata();
Log.d(TAG, "Country DB loaded: " + meta.toString());
Log.d(TAG, "Country DB loaded: " + mCountryReader.getMetadata());
is = mContext.getResources().openRawResource(R.raw.dbip_asn_lite_2021_11_mmdb_gz);
gis = new GZIPInputStream(is);
mAsnReader = new Reader(gis, cache);
Log.d(TAG, "ASN DB loaded: " + meta.toString());
Log.d(TAG, "ASN DB loaded: " + mAsnReader.getMetadata());
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException();

View File

@ -477,10 +477,14 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
}
/* Request a persistent permission to write this URI without invoking the system picker.
* This is needed to write to the URI when invoking PCAPdroid from other apps via Intents. */
* This is needed to write to the URI when invoking PCAPdroid from other apps via Intents
* or when starting the capture at boot. */
if(!hasPermission)
getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Save the URI as a preference
mPrefs.edit().putString(Prefs.PREF_PCAP_URI, mPcapUri.toString()).apply();
Log.d(TAG, "PCAP URI to write: " + mPcapUri.toString());
toggleService();
}
@ -496,9 +500,7 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
private void startCaptureService() {
appStateStarting();
String pcap_uri = ((mPcapUri != null) && (Prefs.getDumpMode(mPrefs) == Prefs.DumpMode.PCAP_FILE)) ? mPcapUri.toString() : "";
mCapHelper.startCapture(new CaptureSettings(mPrefs, pcap_uri));
mCapHelper.startCapture(new CaptureSettings(mPrefs));
}
public void toggleService() {

View File

@ -21,7 +21,7 @@ public class CaptureSettings implements Serializable {
public final String capture_interface;
public final String pcap_uri;
public CaptureSettings(SharedPreferences prefs, String _pcap_uri) {
public CaptureSettings(SharedPreferences prefs) {
dump_mode = Prefs.getDumpMode(prefs);
app_filter = Prefs.getAppFilter(prefs);
collector_address = Prefs.getCollectorIp(prefs);
@ -34,7 +34,7 @@ public class CaptureSettings implements Serializable {
root_capture = Prefs.isRootCaptureEnabled(prefs);
pcapdroid_trailer = Prefs.isPcapdroidTrailerEnabled(prefs);
capture_interface = Prefs.getCaptureInterface(prefs);
pcap_uri = _pcap_uri;
pcap_uri = Prefs.getPCAPUri(prefs);
}
public CaptureSettings(Intent intent) {

View File

@ -49,6 +49,7 @@ public class Prefs {
public static final String PREF_VISUALIZATION_MASK = "vis_mask";
public static final String PREF_MALWARE_WHITELIST = "maware_whitelist";
public static final String PREF_PCAPDROID_TRAILER = "pcapdroid_trailer";
public static final String PREF_START_AT_BOOT = "start_at_boot";
public enum DumpMode {
NONE,
@ -86,4 +87,6 @@ public class Prefs {
return(PCAPdroid.getInstance().getBilling(ctx).isPurchased(Billing.MALWARE_DETECTION_SKU)
&& p.getBoolean(PREF_MALWARE_DETECTION, false));
}
public static boolean startAtBoot(SharedPreferences p) { return(p.getBoolean(PREF_START_AT_BOOT, false)); }
public static String getPCAPUri(SharedPreferences p) { return(p.getString(PREF_PCAP_URI, "")); }
}

View File

@ -212,5 +212,7 @@
<string name="asn">ASN</string>
<string name="country_val">Country: %1$s</string>
<string name="send_report">Send Report</string>
<string name="start_at_boot">Start at boot</string>
<string name="start_at_boot_summary">If enabled, the capture will start automatically when the device boots.</string>
</resources>

View File

@ -90,6 +90,13 @@
app:useSimpleSummaryProvider="true"
app:defaultValue="\@inet" />
<SwitchPreference
app:key="start_at_boot"
android:title="@string/start_at_boot"
app:iconSpaceReserved="false"
app:summary="@string/start_at_boot_summary"
android:defaultValue="false" />
<SwitchPreference
app:key="pcapdroid_trailer"
app:title="@string/pcapdroid_trailer"