summaryrefslogtreecommitdiff
path: root/app/src/main/java/se/leap/bitmaskclient/tor/TorServiceCommand.java
blob: 1946b8610009a64bbc37070f1a31b760fdc1404a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package se.leap.bitmaskclient.tor;

import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;

import androidx.annotation.WorkerThread;

import org.torproject.jni.TorService;

import java.util.concurrent.TimeoutException;

import se.leap.bitmaskclient.base.utils.PreferenceHelper;

import static se.leap.bitmaskclient.tor.TorNotificationManager.TOR_SERVICE_NOTIFICATION_ID;
import static se.leap.bitmaskclient.tor.TorStatusObservable.waitUntil;

public class TorServiceCommand {


    private static String TAG = TorServiceCommand.class.getSimpleName();

    // we bind the service before starting it as foreground service so that we avoid startForeground related RemoteExceptions
    @WorkerThread
    public static boolean startTorService(Context context, String action) throws InterruptedException {
        Log.d(TAG, "startTorService");
        try {
            waitUntil(TorServiceCommand::isNotCancelled, 30);
        } catch (TimeoutException e) {
            e.printStackTrace();
        }
        TorServiceConnection torServiceConnection = initTorServiceConnection(context);
        Log.d(TAG, "startTorService foreground: " + (torServiceConnection != null));
        boolean startedForeground = false;
        if (torServiceConnection == null) {
            return startedForeground;
        }

        try {
            Intent torServiceIntent = new Intent(context, TorService.class);
            torServiceIntent.setAction(action);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Notification notification = TorNotificationManager.buildTorForegroundNotification(context.getApplicationContext());
                //noinspection NewApi
                context.getApplicationContext().startForegroundService(torServiceIntent);
                torServiceConnection.getService().startForeground(TOR_SERVICE_NOTIFICATION_ID, notification);
            } else {
                context.getApplicationContext().startService(torServiceIntent);
            }
            startedForeground = true;
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }

        if (torServiceConnection != null) {
            torServiceConnection.close();
        }

        return startedForeground;
    }

    @WorkerThread
    public static void stopTorService(Context context) {
        if (TorStatusObservable.getStatus() == TorStatusObservable.TorStatus.OFF) {
            return;
        }
        TorStatusObservable.markCancelled();

        try {
            Intent torServiceIntent = new Intent(context, TorService.class);
            torServiceIntent.setAction(TorService.ACTION_STOP);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                //noinspection NewApi
                context.getApplicationContext().startService(torServiceIntent);
            } else {
                context.getApplicationContext().startService(torServiceIntent);
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    public static void stopTorServiceAsync(Context context) {
        TorStatusObservable.markCancelled();
        new Thread(() -> stopTorService(context)).start();
    }

    @WorkerThread
    public static int getHttpTunnelPort(Context context) {
        try {
            TorServiceConnection torServiceConnection = initTorServiceConnection(context);
            if (torServiceConnection != null) {
                int tunnelPort = torServiceConnection.getService().getHttpTunnelPort();
                torServiceConnection.close();
                return tunnelPort;
            }
        } catch (InterruptedException | IllegalStateException e) {
            e.printStackTrace();
        }
        return -1;
    }

    private static boolean isNotCancelled() {
        return !TorStatusObservable.isCancelled();
    }


    private static TorServiceConnection initTorServiceConnection(Context context) throws InterruptedException, IllegalStateException {
        Log.d(TAG, "initTorServiceConnection");
        if (PreferenceHelper.getUseTor(context)) {
            Log.d(TAG, "serviceConnection is still null");
            if (!TorService.hasClientTransportPlugin()) {
                TorService.setClientTransportPlugin(new ClientTransportPlugin(context.getApplicationContext()));
            }
            return new TorServiceConnection(context);
        }
        return null;
    }
}