PageRenderTime 138ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/services/core/java/com/android/server/connectivity/KeepaliveTracker.java

https://gitlab.com/amardeep434/android_frameworks_base_n
Java | 376 lines | 290 code | 41 blank | 45 comment | 54 complexity | 6779df694e2d28726f21cf7f4dfad5d0 MD5 | raw file
  1. /*
  2. * Copyright (C) 2015 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. package com.android.server.connectivity;
  17. import com.android.internal.util.HexDump;
  18. import com.android.internal.util.IndentingPrintWriter;
  19. import com.android.server.connectivity.KeepalivePacketData;
  20. import com.android.server.connectivity.NetworkAgentInfo;
  21. import android.net.ConnectivityManager;
  22. import android.net.ConnectivityManager.PacketKeepalive;
  23. import android.net.LinkAddress;
  24. import android.net.NetworkAgent;
  25. import android.net.NetworkUtils;
  26. import android.net.util.IpUtils;
  27. import android.os.Binder;
  28. import android.os.IBinder;
  29. import android.os.Handler;
  30. import android.os.Message;
  31. import android.os.Messenger;
  32. import android.os.Process;
  33. import android.os.RemoteException;
  34. import android.system.OsConstants;
  35. import android.util.Log;
  36. import android.util.Pair;
  37. import java.nio.ByteBuffer;
  38. import java.nio.ByteOrder;
  39. import java.net.Inet4Address;
  40. import java.net.Inet6Address;
  41. import java.net.InetAddress;
  42. import java.util.ArrayList;
  43. import java.util.HashMap;
  44. import static android.net.ConnectivityManager.PacketKeepalive.*;
  45. import static android.net.NetworkAgent.CMD_START_PACKET_KEEPALIVE;
  46. import static android.net.NetworkAgent.CMD_STOP_PACKET_KEEPALIVE;
  47. import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
  48. /**
  49. * Manages packet keepalive requests.
  50. *
  51. * Provides methods to stop and start keepalive requests, and keeps track of keepalives across all
  52. * networks. This class is tightly coupled to ConnectivityService. It is not thread-safe and its
  53. * methods must be called only from the ConnectivityService handler thread.
  54. */
  55. public class KeepaliveTracker {
  56. private static final String TAG = "KeepaliveTracker";
  57. private static final boolean DBG = true;
  58. public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
  59. /** Keeps track of keepalive requests. */
  60. private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives =
  61. new HashMap<> ();
  62. private final Handler mConnectivityServiceHandler;
  63. public KeepaliveTracker(Handler handler) {
  64. mConnectivityServiceHandler = handler;
  65. }
  66. /**
  67. * Tracks information about a packet keepalive.
  68. *
  69. * All information about this keepalive is known at construction time except the slot number,
  70. * which is only returned when the hardware has successfully started the keepalive.
  71. */
  72. class KeepaliveInfo implements IBinder.DeathRecipient {
  73. // Bookkeping data.
  74. private final Messenger mMessenger;
  75. private final IBinder mBinder;
  76. private final int mUid;
  77. private final int mPid;
  78. private final NetworkAgentInfo mNai;
  79. /** Keepalive slot. A small integer that identifies this keepalive among the ones handled
  80. * by this network. */
  81. private int mSlot = PacketKeepalive.NO_KEEPALIVE;
  82. // Packet data.
  83. private final KeepalivePacketData mPacket;
  84. private final int mInterval;
  85. // Whether the keepalive is started or not.
  86. public boolean isStarted;
  87. public KeepaliveInfo(Messenger messenger, IBinder binder, NetworkAgentInfo nai,
  88. KeepalivePacketData packet, int interval) {
  89. mMessenger = messenger;
  90. mBinder = binder;
  91. mPid = Binder.getCallingPid();
  92. mUid = Binder.getCallingUid();
  93. mNai = nai;
  94. mPacket = packet;
  95. mInterval = interval;
  96. try {
  97. mBinder.linkToDeath(this, 0);
  98. } catch (RemoteException e) {
  99. binderDied();
  100. }
  101. }
  102. public NetworkAgentInfo getNai() {
  103. return mNai;
  104. }
  105. public String toString() {
  106. return new StringBuffer("KeepaliveInfo [")
  107. .append(" network=").append(mNai.network)
  108. .append(" isStarted=").append(isStarted)
  109. .append(" ")
  110. .append(IpUtils.addressAndPortToString(mPacket.srcAddress, mPacket.srcPort))
  111. .append("->")
  112. .append(IpUtils.addressAndPortToString(mPacket.dstAddress, mPacket.dstPort))
  113. .append(" interval=" + mInterval)
  114. .append(" data=" + HexDump.toHexString(mPacket.data))
  115. .append(" uid=").append(mUid).append(" pid=").append(mPid)
  116. .append(" ]")
  117. .toString();
  118. }
  119. /** Sends a message back to the application via its PacketKeepalive.Callback. */
  120. void notifyMessenger(int slot, int err) {
  121. KeepaliveTracker.this.notifyMessenger(mMessenger, slot, err);
  122. }
  123. /** Called when the application process is killed. */
  124. public void binderDied() {
  125. // Not called from ConnectivityService handler thread, so send it a message.
  126. mConnectivityServiceHandler.obtainMessage(
  127. NetworkAgent.CMD_STOP_PACKET_KEEPALIVE,
  128. mSlot, PacketKeepalive.BINDER_DIED, mNai.network).sendToTarget();
  129. }
  130. void unlinkDeathRecipient() {
  131. if (mBinder != null) {
  132. mBinder.unlinkToDeath(this, 0);
  133. }
  134. }
  135. private int checkNetworkConnected() {
  136. if (!mNai.networkInfo.isConnectedOrConnecting()) {
  137. return ERROR_INVALID_NETWORK;
  138. }
  139. return SUCCESS;
  140. }
  141. private int checkSourceAddress() {
  142. // Check that we have the source address.
  143. for (InetAddress address : mNai.linkProperties.getAddresses()) {
  144. if (address.equals(mPacket.srcAddress)) {
  145. return SUCCESS;
  146. }
  147. }
  148. return ERROR_INVALID_IP_ADDRESS;
  149. }
  150. private int checkInterval() {
  151. return mInterval >= 20 ? SUCCESS : ERROR_INVALID_INTERVAL;
  152. }
  153. private int isValid() {
  154. synchronized (mNai) {
  155. int error = checkInterval();
  156. if (error == SUCCESS) error = checkNetworkConnected();
  157. if (error == SUCCESS) error = checkSourceAddress();
  158. return error;
  159. }
  160. }
  161. void start(int slot) {
  162. int error = isValid();
  163. if (error == SUCCESS) {
  164. mSlot = slot;
  165. Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
  166. mNai.asyncChannel.sendMessage(CMD_START_PACKET_KEEPALIVE, slot, mInterval, mPacket);
  167. } else {
  168. notifyMessenger(NO_KEEPALIVE, error);
  169. return;
  170. }
  171. }
  172. void stop(int reason) {
  173. int uid = Binder.getCallingUid();
  174. if (uid != mUid && uid != Process.SYSTEM_UID) {
  175. if (DBG) {
  176. Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
  177. }
  178. }
  179. if (isStarted) {
  180. Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
  181. mNai.asyncChannel.sendMessage(CMD_STOP_PACKET_KEEPALIVE, mSlot);
  182. }
  183. // TODO: at the moment we unconditionally return failure here. In cases where the
  184. // NetworkAgent is alive, should we ask it to reply, so it can return failure?
  185. notifyMessenger(mSlot, reason);
  186. unlinkDeathRecipient();
  187. }
  188. }
  189. void notifyMessenger(Messenger messenger, int slot, int err) {
  190. Message message = Message.obtain();
  191. message.what = EVENT_PACKET_KEEPALIVE;
  192. message.arg1 = slot;
  193. message.arg2 = err;
  194. message.obj = null;
  195. try {
  196. messenger.send(message);
  197. } catch (RemoteException e) {
  198. // Process died?
  199. }
  200. }
  201. private int findFirstFreeSlot(NetworkAgentInfo nai) {
  202. HashMap networkKeepalives = mKeepalives.get(nai);
  203. if (networkKeepalives == null) {
  204. networkKeepalives = new HashMap<Integer, KeepaliveInfo>();
  205. mKeepalives.put(nai, networkKeepalives);
  206. }
  207. // Find the lowest-numbered free slot. Slot numbers start from 1, because that's what two
  208. // separate chipset implementations independently came up with.
  209. int slot;
  210. for (slot = 1; slot <= networkKeepalives.size(); slot++) {
  211. if (networkKeepalives.get(slot) == null) {
  212. return slot;
  213. }
  214. }
  215. return slot;
  216. }
  217. public void handleStartKeepalive(Message message) {
  218. KeepaliveInfo ki = (KeepaliveInfo) message.obj;
  219. NetworkAgentInfo nai = ki.getNai();
  220. int slot = findFirstFreeSlot(nai);
  221. mKeepalives.get(nai).put(slot, ki);
  222. ki.start(slot);
  223. }
  224. public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
  225. HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
  226. if (networkKeepalives != null) {
  227. for (KeepaliveInfo ki : networkKeepalives.values()) {
  228. ki.stop(reason);
  229. }
  230. networkKeepalives.clear();
  231. mKeepalives.remove(nai);
  232. }
  233. }
  234. public void handleStopKeepalive(NetworkAgentInfo nai, int slot, int reason) {
  235. String networkName = (nai == null) ? "(null)" : nai.name();
  236. HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
  237. if (networkKeepalives == null) {
  238. Log.e(TAG, "Attempt to stop keepalive on nonexistent network " + networkName);
  239. return;
  240. }
  241. KeepaliveInfo ki = networkKeepalives.get(slot);
  242. if (ki == null) {
  243. Log.e(TAG, "Attempt to stop nonexistent keepalive " + slot + " on " + networkName);
  244. return;
  245. }
  246. ki.stop(reason);
  247. networkKeepalives.remove(slot);
  248. if (networkKeepalives.isEmpty()) {
  249. mKeepalives.remove(nai);
  250. }
  251. }
  252. public void handleCheckKeepalivesStillValid(NetworkAgentInfo nai) {
  253. HashMap <Integer, KeepaliveInfo> networkKeepalives = mKeepalives.get(nai);
  254. if (networkKeepalives != null) {
  255. ArrayList<Pair<Integer, Integer>> invalidKeepalives = new ArrayList<>();
  256. for (int slot : networkKeepalives.keySet()) {
  257. int error = networkKeepalives.get(slot).isValid();
  258. if (error != SUCCESS) {
  259. invalidKeepalives.add(Pair.create(slot, error));
  260. }
  261. }
  262. for (Pair<Integer, Integer> slotAndError: invalidKeepalives) {
  263. handleStopKeepalive(nai, slotAndError.first, slotAndError.second);
  264. }
  265. }
  266. }
  267. public void handleEventPacketKeepalive(NetworkAgentInfo nai, Message message) {
  268. int slot = message.arg1;
  269. int reason = message.arg2;
  270. KeepaliveInfo ki = null;
  271. try {
  272. ki = mKeepalives.get(nai).get(slot);
  273. } catch(NullPointerException e) {}
  274. if (ki == null) {
  275. Log.e(TAG, "Event for unknown keepalive " + slot + " on " + nai.name());
  276. return;
  277. }
  278. if (reason == SUCCESS && !ki.isStarted) {
  279. // Keepalive successfully started.
  280. if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
  281. ki.isStarted = true;
  282. ki.notifyMessenger(slot, reason);
  283. } else {
  284. // Keepalive successfully stopped, or error.
  285. ki.isStarted = false;
  286. if (reason == SUCCESS) {
  287. if (DBG) Log.d(TAG, "Successfully stopped keepalive " + slot + " on " + nai.name());
  288. } else {
  289. if (DBG) Log.d(TAG, "Keepalive " + slot + " on " + nai.name() + " error " + reason);
  290. }
  291. handleStopKeepalive(nai, slot, reason);
  292. }
  293. }
  294. public void startNattKeepalive(NetworkAgentInfo nai, int intervalSeconds, Messenger messenger,
  295. IBinder binder, String srcAddrString, int srcPort, String dstAddrString, int dstPort) {
  296. if (nai == null) {
  297. notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK);
  298. return;
  299. }
  300. InetAddress srcAddress, dstAddress;
  301. try {
  302. srcAddress = NetworkUtils.numericToInetAddress(srcAddrString);
  303. dstAddress = NetworkUtils.numericToInetAddress(dstAddrString);
  304. } catch (IllegalArgumentException e) {
  305. notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_IP_ADDRESS);
  306. return;
  307. }
  308. KeepalivePacketData packet;
  309. try {
  310. packet = KeepalivePacketData.nattKeepalivePacket(
  311. srcAddress, srcPort, dstAddress, NATT_PORT);
  312. } catch (KeepalivePacketData.InvalidPacketException e) {
  313. notifyMessenger(messenger, NO_KEEPALIVE, e.error);
  314. return;
  315. }
  316. KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds);
  317. Log.d(TAG, "Created keepalive: " + ki.toString());
  318. mConnectivityServiceHandler.obtainMessage(
  319. NetworkAgent.CMD_START_PACKET_KEEPALIVE, ki).sendToTarget();
  320. }
  321. public void dump(IndentingPrintWriter pw) {
  322. pw.println("Packet keepalives:");
  323. pw.increaseIndent();
  324. for (NetworkAgentInfo nai : mKeepalives.keySet()) {
  325. pw.println(nai.name());
  326. pw.increaseIndent();
  327. for (int slot : mKeepalives.get(nai).keySet()) {
  328. KeepaliveInfo ki = mKeepalives.get(nai).get(slot);
  329. pw.println(slot + ": " + ki.toString());
  330. }
  331. pw.decreaseIndent();
  332. }
  333. pw.decreaseIndent();
  334. }
  335. }