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