1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.googlecode.android_scripting.facade.net;
18 
19 import android.app.Service;
20 import android.content.Context;
21 import android.net.ConnectivityManager;
22 import android.net.IpSecManager.UdpEncapsulationSocket;
23 import android.net.Network;
24 import android.net.NetworkCapabilities;
25 import android.net.SocketKeepalive;
26 import android.net.util.KeepaliveUtils;
27 
28 import com.googlecode.android_scripting.Log;
29 import com.googlecode.android_scripting.facade.ConnectivityConstants;
30 import com.googlecode.android_scripting.facade.ConnectivityEvents.SocketKeepaliveEvent;
31 import com.googlecode.android_scripting.facade.EventFacade;
32 import com.googlecode.android_scripting.facade.FacadeManager;
33 import com.googlecode.android_scripting.jsonrpc.RpcReceiver;
34 import com.googlecode.android_scripting.rpc.Rpc;
35 
36 import java.net.InetAddress;
37 import java.net.Socket;
38 import java.net.UnknownHostException;
39 import java.util.HashMap;
40 import java.util.concurrent.Executor;
41 import java.util.concurrent.Executors;
42 
43 /**
44  * Socket keepalive SL4A APIs
45  */
46 public class SocketKeepaliveFacade extends RpcReceiver {
47 
48     private enum Event {
49         Invalid(0),
50         Started(1 << 0),
51         Stopped(1 << 1),
52         Error(1 << 2),
53         OnDataReceived(1 << 3),
54         EventAll(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
55 
56         private int mType;
Event(int type)57         Event(int type) {
58             mType = type;
59         }
getType()60         private int getType() {
61             return mType;
62         }
63     }
64 
65     class SocketKeepaliveReceiver extends SocketKeepalive.Callback {
66 
67         private int mEvents;
68         public String mId;
69         public SocketKeepalive mSocketKeepalive;
70 
SocketKeepaliveReceiver(int events)71         SocketKeepaliveReceiver(int events) {
72             super();
73             mEvents = events;
74             mId = this.toString();
75         }
76 
startListeningForEvents(int events)77         public void startListeningForEvents(int events) {
78             mEvents |= events & Event.EventAll.getType();
79         }
80 
stopListeningForEvents(int events)81         public void stopListeningForEvents(int events) {
82             mEvents &= ~(events & Event.EventAll.getType());
83         }
84 
handleEvent(Event e)85         private void handleEvent(Event e) {
86             Log.d("SocketKeepaliveFacade: SocketKeepaliveCallback - " + e.toString());
87             if ((mEvents & e.getType()) == e.getType()) {
88                 mEventFacade.postEvent(
89                         ConnectivityConstants.EventSocketKeepaliveCallback,
90                         new SocketKeepaliveEvent(mId, e.toString()));
91             }
92         }
93 
94         @Override
onStarted()95         public void onStarted() {
96             handleEvent(Event.Started);
97         }
98 
99         @Override
onStopped()100         public void onStopped() {
101             handleEvent(Event.Stopped);
102         }
103 
104         @Override
onError(int error)105         public void onError(int error) {
106             handleEvent(Event.Error);
107         }
108 
109         @Override
onDataReceived()110         public void onDataReceived() {
111             handleEvent(Event.OnDataReceived);
112         }
113     }
114 
115     private final ConnectivityManager mManager;
116     private final Service mService;
117     private final Context mContext;
118     private final EventFacade mEventFacade;
119     private static HashMap<String, SocketKeepaliveReceiver> sSocketKeepaliveReceiverMap =
120             new HashMap<String, SocketKeepaliveReceiver>();
121     private final Executor mExecutor = Executors.newSingleThreadExecutor();
SocketKeepaliveFacade(FacadeManager manager)122     public SocketKeepaliveFacade(FacadeManager manager) {
123         super(manager);
124         mService = manager.getService();
125         mContext = mService.getBaseContext();
126         mManager = (ConnectivityManager) mService.getSystemService(Context.CONNECTIVITY_SERVICE);
127         mEventFacade = manager.getReceiver(EventFacade.class);
128     }
129 
130     /**
131      * Start NATT socket keepalive
132      * @param udpEncapsulationSocketId : hash key of {@link UdpEncapsulationSocket}
133      * @param srcAddrString : source addr in string
134      * @param dstAddrString : destination addr in string
135      * @param intervalSeconds : keepalive interval in seconds
136      * @return Keepalive key if successful, null if not
137      */
138     @Rpc(description = "start natt socket keepalive")
startNattSocketKeepalive( String udpEncapsulationSocketId, String srcAddrString, String dstAddrString, Integer intervalSeconds)139     public String startNattSocketKeepalive(
140             String udpEncapsulationSocketId,
141             String srcAddrString,
142             String dstAddrString,
143             Integer intervalSeconds) {
144         try {
145             UdpEncapsulationSocket udpEncapSocket =
146                     IpSecManagerFacade.getUdpEncapsulationSocket(udpEncapsulationSocketId);
147             Network network = mManager.getActiveNetwork();
148             InetAddress srcAddr = InetAddress.getByName(srcAddrString);
149             InetAddress dstAddr = InetAddress.getByName(dstAddrString);
150             Log.d("SocketKeepaliveFacade: startNattKeepalive intervalSeconds:" + intervalSeconds);
151             SocketKeepaliveReceiver socketKeepaliveReceiver = new SocketKeepaliveReceiver(
152                     Event.EventAll.getType());
153             SocketKeepalive socketKeepalive = mManager.createSocketKeepalive(
154                     network,
155                     udpEncapSocket,
156                     srcAddr,
157                     dstAddr,
158                     mExecutor,
159                     socketKeepaliveReceiver);
160             socketKeepalive.start(intervalSeconds);
161             if (socketKeepalive != null) {
162                 socketKeepaliveReceiver.mSocketKeepalive = socketKeepalive;
163                 String key = socketKeepaliveReceiver.mId;
164                 sSocketKeepaliveReceiverMap.put(key, socketKeepaliveReceiver);
165                 return key;
166             } else {
167                 Log.e("SocketKeepaliveFacade: Failed to start Natt socketkeepalive");
168                 return null;
169             }
170         } catch (UnknownHostException e) {
171             Log.e("SocketKeepaliveFacade: SocketNattKeepalive exception", e);
172             return null;
173         }
174     }
175 
176     /**
177      * Start TCP socket keepalive
178      * @param socketId : Hash key of socket object
179      * @param intervalSeconds : keepalive interval in seconds
180      * @return Keepalive key if successful, null if not
181      */
182     @Rpc(description = "Start TCP socket keepalive")
startTcpSocketKeepalive(String socketId, Integer intervalSeconds)183     public String startTcpSocketKeepalive(String socketId, Integer intervalSeconds) {
184         Socket socket = SocketFacade.getSocket(socketId);
185         Network network = mManager.getActiveNetwork();
186         Log.d("SocketKeepaliveFacade: Keepalive interval seconds: " + intervalSeconds);
187         SocketKeepaliveReceiver socketKeepaliveReceiver = new SocketKeepaliveReceiver(
188                 Event.EventAll.getType());
189         SocketKeepalive socketKeepalive = mManager.createSocketKeepalive(
190                 network,
191                 socket,
192                 mExecutor,
193                 socketKeepaliveReceiver);
194         socketKeepalive.start(intervalSeconds);
195         if (socketKeepalive == null) {
196             Log.e("SocketKeepaliveFacade: Failed to start TCP SocketKeepalive");
197             return null;
198         }
199         socketKeepaliveReceiver.mSocketKeepalive = socketKeepalive;
200         String key = socketKeepaliveReceiver.mId;
201         sSocketKeepaliveReceiverMap.put(key, socketKeepaliveReceiver);
202         return key;
203     }
204 
205     /**
206      * Stop socket keepalive
207      * @param key : {@link SocketKeepaliveReceiver}
208      * @return true if stopping keepalive is successful, false if not
209      */
210     @Rpc(description = "stop socket keepalive")
stopSocketKeepalive(String key)211     public Boolean stopSocketKeepalive(String key) {
212         SocketKeepaliveReceiver mSocketKeepaliveReceiver =
213                 sSocketKeepaliveReceiverMap.get(key);
214         if (mSocketKeepaliveReceiver == null) {
215             return false;
216         }
217         mSocketKeepaliveReceiver.mSocketKeepalive.stop();
218         return true;
219     }
220 
221     /**
222      * Remove key from the SocketKeepaliveReceiver map
223      * @param key : Hash key of the keepalive object
224      */
225     @Rpc(description = "remove SocketKeepaliveReceiver key")
removeSocketKeepaliveReceiverKey(String key)226     public void removeSocketKeepaliveReceiverKey(String key) {
227         sSocketKeepaliveReceiverMap.remove(key);
228     }
229 
230     /**
231      * Start listening for a socket keepalive event
232      * @param key : hash key of {@link SocketKeepaliveReceiver}
233      * @param eventString : type of keepalive event - Started, Stopped, Error
234      * @return True if listening for event successful, false if not
235      */
236     @Rpc(description = "start listening for SocketKeepalive Event")
socketKeepaliveStartListeningForEvent(String key, String eventString)237     public Boolean socketKeepaliveStartListeningForEvent(String key, String eventString) {
238         SocketKeepaliveReceiver mSocketKeepaliveReceiver =
239                 sSocketKeepaliveReceiverMap.get(key);
240         int event = Event.valueOf(eventString).getType();
241         if (mSocketKeepaliveReceiver == null || event == Event.Invalid.getType()) {
242             return false;
243         }
244         mSocketKeepaliveReceiver.startListeningForEvents(event);
245         return true;
246     }
247 
248     /**
249      * Stop listening for a for socket keepalive event
250      * @param key : hash key of {@link SocketKeepaliveReceiver}
251      * @param eventString : type of keepalive event - Started, Stopped, Error
252      * @return True if listening event successful, false if not
253      */
254     @Rpc(description = "stop listening for SocketKeepalive Event")
socketKeepaliveStopListeningForEvent(String key, String eventString)255     public Boolean socketKeepaliveStopListeningForEvent(String key, String eventString) {
256         SocketKeepaliveReceiver mSocketKeepaliveReceiver =
257                 sSocketKeepaliveReceiverMap.get(key);
258         int event = Event.valueOf(eventString).getType();
259         if (mSocketKeepaliveReceiver == null || event == Event.Invalid.getType()) {
260             return false;
261         }
262         mSocketKeepaliveReceiver.stopListeningForEvents(event);
263         return true;
264     }
265 
266     /**
267      * Get maximum supported keepalives for active network
268      * @return Max number of keepalives supported in int
269      */
270     @Rpc(description = "get max number of keepalives supported for active network")
getSupportedKeepalivesForNetwork()271     public int getSupportedKeepalivesForNetwork() {
272         NetworkCapabilities netCap = mManager.getNetworkCapabilities(mManager.getActiveNetwork());
273         int[] ka = KeepaliveUtils.getSupportedKeepalives(mContext);
274         return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities(ka, netCap);
275     }
276 
277     @Override
shutdown()278     public void shutdown() {}
279 }
280