5
5
6
6
package com .wireguard .android .backend ;
7
7
8
+ import android .app .ForegroundServiceStartNotAllowedException ;
9
+ import android .app .Notification ;
10
+ import android .app .NotificationChannel ;
11
+ import android .app .NotificationManager ;
8
12
import android .content .Context ;
9
13
import android .content .Intent ;
14
+ import android .content .pm .ServiceInfo ;
10
15
import android .os .Build ;
11
16
import android .os .ParcelFileDescriptor ;
12
17
import android .system .OsConstants ;
24
29
import com .wireguard .util .NonNullForAll ;
25
30
26
31
import java .net .InetAddress ;
27
- import java .time .Instant ;
28
32
import java .util .Collections ;
29
33
import java .util .Set ;
30
34
import java .util .concurrent .ExecutionException ;
35
39
36
40
import androidx .annotation .Nullable ;
37
41
import androidx .collection .ArraySet ;
42
+ import androidx .core .app .NotificationCompat ;
43
+ import androidx .core .app .ServiceCompat ;
38
44
39
45
/**
40
46
* Implementation of {@link Backend} that uses the wireguard-go userspace implementation to provide
@@ -392,6 +398,9 @@ public GhettoCompletableFuture<V> newIncompleteFuture() {
392
398
* {@link android.net.VpnService} implementation for {@link GoBackend}
393
399
*/
394
400
public static class VpnService extends android .net .VpnService {
401
+
402
+ private static final int NOTIFICATION_ID = 999 ;
403
+ private static final String CHANNEL_ID = "WireGuardChannel" ;
395
404
@ Nullable private GoBackend owner ;
396
405
397
406
public Builder getBuilder () {
@@ -423,6 +432,7 @@ public void onDestroy() {
423
432
424
433
@ Override
425
434
public int onStartCommand (@ Nullable final Intent intent , final int flags , final int startId ) {
435
+ startForeground ();
426
436
vpnService .complete (this );
427
437
if (intent == null || intent .getComponent () == null || !intent .getComponent ().getPackageName ().equals (getPackageName ())) {
428
438
Log .d (TAG , "Service started by Always-on VPN feature" );
@@ -435,5 +445,42 @@ public int onStartCommand(@Nullable final Intent intent, final int flags, final
435
445
public void setOwner (final GoBackend owner ) {
436
446
this .owner = owner ;
437
447
}
448
+
449
+ private void startForeground () {
450
+ try {
451
+ createNotificationChannel ();
452
+ final Notification notification = new NotificationCompat
453
+ .Builder (this , CHANNEL_ID )
454
+ .build ();
455
+ ServiceCompat .startForeground (this , NOTIFICATION_ID , notification , ServiceInfo .FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED );
456
+ } catch (final Exception ex ) {
457
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .S &&
458
+ ex instanceof ForegroundServiceStartNotAllowedException
459
+ ) {
460
+ Log .d (TAG , "App not in a valid state to start foreground service" );
461
+ }
462
+ }
463
+ }
464
+
465
+ private void createNotificationChannel () {
466
+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
467
+ final NotificationManager notificationManager =
468
+ (NotificationManager ) getSystemService (Context .NOTIFICATION_SERVICE );
469
+
470
+ if (notificationManager .getNotificationChannel (CHANNEL_ID ) == null ) {
471
+ final NotificationChannel channel = new NotificationChannel (
472
+ CHANNEL_ID ,
473
+ "WireGuard VPN Service" ,
474
+ NotificationManager .IMPORTANCE_LOW
475
+ );
476
+ channel .setDescription ("VPN connection status notifications" );
477
+ channel .setShowBadge (false );
478
+ channel .enableLights (false );
479
+ channel .enableVibration (false );
480
+
481
+ notificationManager .createNotificationChannel (channel );
482
+ }
483
+ }
484
+ }
438
485
}
439
486
}
0 commit comments