Skip to content

Commit 287c2aa

Browse files
authored
android: make foreground notification call synchronous, and use exped… (#736)
android: make foreground notification call synchronous, and use expedited work -Stop using Dispatchers.IO for showing foreground notifications, since the scheduling can introduce delays for work that we want done immediately -Make WorkManager expedited to avoid delaying/losing tasks scheduled when the app is backgrounded/immediately Updates tailscale/tailscale#14148 Signed-off-by: kari-ts <kari@tailscale.com>
1 parent afc295d commit 287c2aa

File tree

2 files changed

+48
-16
lines changed

2 files changed

+48
-16
lines changed

android/src/main/java/com/tailscale/ipn/IPNReceiver.java

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@
66
import android.content.BroadcastReceiver;
77
import android.content.Context;
88
import android.content.Intent;
9-
import androidx.work.Data;
109

10+
import androidx.work.Data;
11+
import androidx.work.ExistingWorkPolicy;
1112
import androidx.work.OneTimeWorkRequest;
13+
import androidx.work.OutOfQuotaPolicy;
1214
import androidx.work.WorkManager;
1315

1416
import java.util.Objects;
@@ -20,26 +22,56 @@ public class IPNReceiver extends BroadcastReceiver {
2022

2123
public static final String INTENT_CONNECT_VPN = "com.tailscale.ipn.CONNECT_VPN";
2224
public static final String INTENT_DISCONNECT_VPN = "com.tailscale.ipn.DISCONNECT_VPN";
23-
2425
private static final String INTENT_USE_EXIT_NODE = "com.tailscale.ipn.USE_EXIT_NODE";
2526

27+
// Unique work names prevent connect/disconnect flapping from enqueuing a long backlog.
28+
private static final String WORK_CONNECT = "ipn-connect-vpn";
29+
private static final String WORK_DISCONNECT = "ipn-disconnect-vpn";
30+
private static final String WORK_USE_EXIT_NODE = "ipn-use-exit-node";
31+
2632
@Override
2733
public void onReceive(Context context, Intent intent) {
28-
WorkManager workManager = WorkManager.getInstance(context);
34+
if (intent == null) return;
2935

30-
// On the relevant action, start the relevant worker, which can stay active for longer than this receiver can.
31-
if (Objects.equals(intent.getAction(), INTENT_CONNECT_VPN)) {
32-
workManager.enqueue(new OneTimeWorkRequest.Builder(StartVPNWorker.class).build());
33-
} else if (Objects.equals(intent.getAction(), INTENT_DISCONNECT_VPN)) {
34-
workManager.enqueue(new OneTimeWorkRequest.Builder(StopVPNWorker.class).build());
35-
}
36-
else if (Objects.equals(intent.getAction(), INTENT_USE_EXIT_NODE)) {
36+
final WorkManager workManager = WorkManager.getInstance(context);
37+
final String action = intent.getAction();
38+
39+
if (Objects.equals(action, INTENT_CONNECT_VPN)) {
40+
OneTimeWorkRequest req =
41+
new OneTimeWorkRequest.Builder(StartVPNWorker.class)
42+
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
43+
.addTag(WORK_CONNECT)
44+
.build();
45+
46+
workManager.enqueueUniqueWork(WORK_CONNECT, ExistingWorkPolicy.REPLACE, req);
47+
48+
} else if (Objects.equals(action, INTENT_DISCONNECT_VPN)) {
49+
OneTimeWorkRequest req =
50+
new OneTimeWorkRequest.Builder(StopVPNWorker.class)
51+
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
52+
.addTag(WORK_DISCONNECT)
53+
.build();
54+
55+
workManager.enqueueUniqueWork(WORK_DISCONNECT, ExistingWorkPolicy.REPLACE, req);
56+
57+
} else if (Objects.equals(action, INTENT_USE_EXIT_NODE)) {
3758
String exitNode = intent.getStringExtra("exitNode");
3859
boolean allowLanAccess = intent.getBooleanExtra("allowLanAccess", false);
39-
Data.Builder workData = new Data.Builder();
40-
workData.putString(UseExitNodeWorker.EXIT_NODE_NAME, exitNode);
41-
workData.putBoolean(UseExitNodeWorker.ALLOW_LAN_ACCESS, allowLanAccess);
42-
workManager.enqueue(new OneTimeWorkRequest.Builder(UseExitNodeWorker.class).setInputData(workData.build()).build());
60+
61+
Data input =
62+
new Data.Builder()
63+
.putString(UseExitNodeWorker.EXIT_NODE_NAME, exitNode)
64+
.putBoolean(UseExitNodeWorker.ALLOW_LAN_ACCESS, allowLanAccess)
65+
.build();
66+
67+
OneTimeWorkRequest req =
68+
new OneTimeWorkRequest.Builder(UseExitNodeWorker.class)
69+
.setInputData(input)
70+
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
71+
.addTag(WORK_USE_EXIT_NODE)
72+
.build();
73+
74+
workManager.enqueueUniqueWork(WORK_USE_EXIT_NODE, ExistingWorkPolicy.REPLACE, req);
4375
}
4476
}
4577
}

android/src/main/java/com/tailscale/ipn/IPNService.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ open class IPNService : VpnService(), libtailscale.IPNService {
5454
START_NOT_STICKY
5555
}
5656
ACTION_START_VPN -> {
57-
scope.launch { showForegroundNotification() }
57+
showForegroundNotification()
5858
app.setWantRunning(true)
5959
Libtailscale.requestVPN(this)
6060
START_STICKY
@@ -78,7 +78,7 @@ open class IPNService : VpnService(), libtailscale.IPNService {
7878
// This means that we were restarted after the service was killed
7979
// (potentially due to OOM).
8080
if (UninitializedApp.get().isAbleToStartVPN()) {
81-
scope.launch { showForegroundNotification() }
81+
showForegroundNotification()
8282
App.get()
8383
Libtailscale.requestVPN(this)
8484
START_STICKY

0 commit comments

Comments
 (0)