1 /*
2  * Copyright (C) 2011 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.android.internal.telephony.dataconnection;
18 
19 import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
20 import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
21 import com.android.internal.util.AsyncChannel;
22 import com.android.internal.util.Protocol;
23 
24 import android.net.LinkProperties;
25 import android.net.NetworkCapabilities;
26 import android.net.ProxyInfo;
27 import android.os.Message;
28 
29 /**
30  * AsyncChannel to a DataConnection
31  */
32 public class DcAsyncChannel extends AsyncChannel {
33     private static final boolean DBG = false;
34     private String mLogTag;
35 
36     private DataConnection mDc;
37     private long mDcThreadId;
38 
39     public static final int BASE = Protocol.BASE_DATA_CONNECTION_AC;
40 
41     public static final int REQ_IS_INACTIVE = BASE + 0;
42     public static final int RSP_IS_INACTIVE = BASE + 1;
43 
44     public static final int REQ_GET_CID = BASE + 2;
45     public static final int RSP_GET_CID = BASE + 3;
46 
47     public static final int REQ_GET_APNSETTING = BASE + 4;
48     public static final int RSP_GET_APNSETTING = BASE + 5;
49 
50     public static final int REQ_GET_LINK_PROPERTIES = BASE + 6;
51     public static final int RSP_GET_LINK_PROPERTIES = BASE + 7;
52 
53     public static final int REQ_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 8;
54     public static final int RSP_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 9;
55 
56     public static final int REQ_GET_NETWORK_CAPABILITIES = BASE + 10;
57     public static final int RSP_GET_NETWORK_CAPABILITIES = BASE + 11;
58 
59     public static final int REQ_RESET = BASE + 12;
60     public static final int RSP_RESET = BASE + 13;
61 
62     private static final int CMD_TO_STRING_COUNT = RSP_RESET - BASE + 1;
63     private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
64     static {
65         sCmdToString[REQ_IS_INACTIVE - BASE] = "REQ_IS_INACTIVE";
66         sCmdToString[RSP_IS_INACTIVE - BASE] = "RSP_IS_INACTIVE";
67         sCmdToString[REQ_GET_CID - BASE] = "REQ_GET_CID";
68         sCmdToString[RSP_GET_CID - BASE] = "RSP_GET_CID";
69         sCmdToString[REQ_GET_APNSETTING - BASE] = "REQ_GET_APNSETTING";
70         sCmdToString[RSP_GET_APNSETTING - BASE] = "RSP_GET_APNSETTING";
71         sCmdToString[REQ_GET_LINK_PROPERTIES - BASE] = "REQ_GET_LINK_PROPERTIES";
72         sCmdToString[RSP_GET_LINK_PROPERTIES - BASE] = "RSP_GET_LINK_PROPERTIES";
73         sCmdToString[REQ_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
74                 "REQ_SET_LINK_PROPERTIES_HTTP_PROXY";
75         sCmdToString[RSP_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
76                 "RSP_SET_LINK_PROPERTIES_HTTP_PROXY";
77         sCmdToString[REQ_GET_NETWORK_CAPABILITIES - BASE] = "REQ_GET_NETWORK_CAPABILITIES";
78         sCmdToString[RSP_GET_NETWORK_CAPABILITIES - BASE] = "RSP_GET_NETWORK_CAPABILITIES";
79         sCmdToString[REQ_RESET - BASE] = "REQ_RESET";
80         sCmdToString[RSP_RESET - BASE] = "RSP_RESET";
81     }
82 
83     // Convert cmd to string or null if unknown
cmdToString(int cmd)84     protected static String cmdToString(int cmd) {
85         cmd -= BASE;
86         if ((cmd >= 0) && (cmd < sCmdToString.length)) {
87             return sCmdToString[cmd];
88         } else {
89             return AsyncChannel.cmdToString(cmd + BASE);
90         }
91     }
92 
93     /**
94      * enum used to notify action taken or necessary to be
95      * taken after the link property is changed.
96      */
97     public enum LinkPropertyChangeAction {
98         NONE, CHANGED, RESET;
99 
fromInt(int value)100         public static LinkPropertyChangeAction fromInt(int value) {
101             if (value == NONE.ordinal()) {
102                 return NONE;
103             } else if (value == CHANGED.ordinal()) {
104                 return CHANGED;
105             } else if (value == RESET.ordinal()) {
106                 return RESET;
107             } else {
108                 throw new RuntimeException("LinkPropertyChangeAction.fromInt: bad value=" + value);
109             }
110         }
111     }
112 
DcAsyncChannel(DataConnection dc, String logTag)113     public DcAsyncChannel(DataConnection dc, String logTag) {
114         mDc = dc;
115         mDcThreadId = mDc.getHandler().getLooper().getThread().getId();
116         mLogTag = logTag;
117     }
118 
119     /**
120      * Request if the state machine is in the inactive state.
121      * Response {@link #rspIsInactive}
122      */
reqIsInactive()123     public void reqIsInactive() {
124         sendMessage(REQ_IS_INACTIVE);
125         if (DBG) log("reqIsInactive");
126     }
127 
128     /**
129      * Evaluate RSP_IS_INACTIVE.
130      *
131      * @return true if the state machine is in the inactive state.
132      */
rspIsInactive(Message response)133     public boolean rspIsInactive(Message response) {
134         boolean retVal = response.arg1 == 1;
135         if (DBG) log("rspIsInactive=" + retVal);
136         return retVal;
137     }
138 
139     /**
140      * @return true if the state machine is in the inactive state
141      * and can be used for a new connection.
142      */
isInactiveSync()143     public boolean isInactiveSync() {
144         boolean value;
145         if (isCallerOnDifferentThread()) {
146             Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
147             if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
148                 value = rspIsInactive(response);
149             } else {
150                 log("rspIsInactive error response=" + response);
151                 value = false;
152             }
153         } else {
154             value = mDc.getIsInactive();
155         }
156         return value;
157     }
158 
159     /**
160      * Request the Connection ID.
161      * Response {@link #rspCid}
162      */
reqCid()163     public void reqCid() {
164         sendMessage(REQ_GET_CID);
165         if (DBG) log("reqCid");
166     }
167 
168     /**
169      * Evaluate a RSP_GET_CID message and return the cid.
170      *
171      * @param response Message
172      * @return connection id or -1 if an error
173      */
rspCid(Message response)174     public int rspCid(Message response) {
175         int retVal = response.arg1;
176         if (DBG) log("rspCid=" + retVal);
177         return retVal;
178     }
179 
180     /**
181      * @return connection id or -1 if an error
182      */
getCidSync()183     public int getCidSync() {
184         int value;
185         if (isCallerOnDifferentThread()) {
186             Message response = sendMessageSynchronously(REQ_GET_CID);
187             if ((response != null) && (response.what == RSP_GET_CID)) {
188                 value = rspCid(response);
189             } else {
190                 log("rspCid error response=" + response);
191                 value = -1;
192             }
193         } else {
194             value = mDc.getCid();
195         }
196         return value;
197     }
198 
199     /**
200      * Request the connections ApnSetting.
201      * Response {@link #rspApnSetting}
202      */
reqApnSetting()203     public void reqApnSetting() {
204         sendMessage(REQ_GET_APNSETTING);
205         if (DBG) log("reqApnSetting");
206     }
207 
208     /**
209      * Evaluate a RSP_APN_SETTING message and return the ApnSetting.
210      *
211      * @param response Message
212      * @return ApnSetting, maybe null
213      */
rspApnSetting(Message response)214     public ApnSetting rspApnSetting(Message response) {
215         ApnSetting retVal = (ApnSetting) response.obj;
216         if (DBG) log("rspApnSetting=" + retVal);
217         return retVal;
218     }
219 
220     /**
221      * Get the connections ApnSetting.
222      *
223      * @return ApnSetting or null if an error
224      */
getApnSettingSync()225     public ApnSetting getApnSettingSync() {
226         ApnSetting value;
227         if (isCallerOnDifferentThread()) {
228             Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
229             if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
230                 value = rspApnSetting(response);
231             } else {
232                 log("getApnSetting error response=" + response);
233                 value = null;
234             }
235         } else {
236             value = mDc.getApnSetting();
237         }
238         return value;
239     }
240 
241     /**
242      * Request the connections LinkProperties.
243      * Response {@link #rspLinkProperties}
244      */
reqLinkProperties()245     public void reqLinkProperties() {
246         sendMessage(REQ_GET_LINK_PROPERTIES);
247         if (DBG) log("reqLinkProperties");
248     }
249 
250     /**
251      * Evaluate RSP_GET_LINK_PROPERTIES
252      *
253      * @param response
254      * @return LinkProperties, maybe null.
255      */
rspLinkProperties(Message response)256     public LinkProperties rspLinkProperties(Message response) {
257         LinkProperties retVal = (LinkProperties) response.obj;
258         if (DBG) log("rspLinkProperties=" + retVal);
259         return retVal;
260     }
261 
262     /**
263      * Get the connections LinkProperties.
264      *
265      * @return LinkProperties or null if an error
266      */
getLinkPropertiesSync()267     public LinkProperties getLinkPropertiesSync() {
268         LinkProperties value;
269         if (isCallerOnDifferentThread()) {
270             Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
271             if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
272                 value = rspLinkProperties(response);
273             } else {
274                 log("getLinkProperties error response=" + response);
275                 value = null;
276             }
277         } else {
278             value = mDc.getCopyLinkProperties();
279         }
280         return value;
281     }
282 
283     /**
284      * Request setting the connections LinkProperties.HttpProxy.
285      * Response RSP_SET_LINK_PROPERTIES when complete.
286      */
reqSetLinkPropertiesHttpProxy(ProxyInfo proxy)287     public void reqSetLinkPropertiesHttpProxy(ProxyInfo proxy) {
288         sendMessage(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
289         if (DBG) log("reqSetLinkPropertiesHttpProxy proxy=" + proxy);
290     }
291 
292     /**
293      * Set the connections LinkProperties.HttpProxy
294      */
setLinkPropertiesHttpProxySync(ProxyInfo proxy)295     public void setLinkPropertiesHttpProxySync(ProxyInfo proxy) {
296         if (isCallerOnDifferentThread()) {
297             Message response =
298                 sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
299             if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
300                 if (DBG) log("setLinkPropertiesHttpPoxy ok");
301             } else {
302                 log("setLinkPropertiesHttpPoxy error response=" + response);
303             }
304         } else {
305             mDc.setLinkPropertiesHttpProxy(proxy);
306         }
307     }
308 
309     /**
310      * Request the connections NetworkCapabilities.
311      * Response {@link #rspNetworkCapabilities}
312      */
reqNetworkCapabilities()313     public void reqNetworkCapabilities() {
314         sendMessage(REQ_GET_NETWORK_CAPABILITIES);
315         if (DBG) log("reqNetworkCapabilities");
316     }
317 
318     /**
319      * Evaluate RSP_GET_NETWORK_CAPABILITIES
320      *
321      * @param response
322      * @return NetworkCapabilites, maybe null.
323      */
rspNetworkCapabilities(Message response)324     public NetworkCapabilities rspNetworkCapabilities(Message response) {
325         NetworkCapabilities retVal = (NetworkCapabilities) response.obj;
326         if (DBG) log("rspNetworkCapabilities=" + retVal);
327         return retVal;
328     }
329 
330     /**
331      * Get the connections NetworkCapabilities.
332      *
333      * @return NetworkCapabilities or null if an error
334      */
getNetworkCapabilitiesSync()335     public NetworkCapabilities getNetworkCapabilitiesSync() {
336         NetworkCapabilities value;
337         if (isCallerOnDifferentThread()) {
338             Message response = sendMessageSynchronously(REQ_GET_NETWORK_CAPABILITIES);
339             if ((response != null) && (response.what == RSP_GET_NETWORK_CAPABILITIES)) {
340                 value = rspNetworkCapabilities(response);
341             } else {
342                 value = null;
343             }
344         } else {
345             value = mDc.getCopyNetworkCapabilities();
346         }
347         return value;
348     }
349 
350     /**
351      * Response RSP_RESET when complete
352      */
reqReset()353     public void reqReset() {
354         sendMessage(REQ_RESET);
355         if (DBG) log("reqReset");
356     }
357 
358     /**
359      * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
360      * Used for cellular networks that use Acesss Point Names (APN) such
361      * as GSM networks.
362      *
363      * @param apnContext is the Access Point Name to bring up a connection to
364      * @param initialMaxRetry the number of retires for initial bringup.
365      * @param profileId for the conneciton
366      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
367      *        With AsyncResult.userObj set to the original msg.obj,
368      *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
369      */
bringUp(ApnContext apnContext, int initialMaxRetry, int profileId, int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg)370     public void bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,
371             int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg) {
372         if (DBG) {
373             log("bringUp: apnContext=" + apnContext + " initialMaxRetry=" + initialMaxRetry
374                 + " onCompletedMsg=" + onCompletedMsg);
375         }
376         sendMessage(DataConnection.EVENT_CONNECT,
377                     new ConnectionParams(apnContext, initialMaxRetry, profileId,
378                             rilRadioTechnology, retryWhenSSChange, onCompletedMsg));
379     }
380 
381     /**
382      * Tear down the connection through the apn on the network.
383      *
384      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
385      *        With AsyncResult.userObj set to the original msg.obj.
386      */
tearDown(ApnContext apnContext, String reason, Message onCompletedMsg)387     public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) {
388         if (DBG) {
389             log("tearDown: apnContext=" + apnContext
390                     + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
391         }
392         sendMessage(DataConnection.EVENT_DISCONNECT,
393                         new DisconnectParams(apnContext, reason, onCompletedMsg));
394     }
395 
396     /**
397      * Tear down the connection through the apn on the network.  Ignores refcount and
398      * and always tears down.
399      *
400      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
401      *        With AsyncResult.userObj set to the original msg.obj.
402      */
tearDownAll(String reason, Message onCompletedMsg)403     public void tearDownAll(String reason, Message onCompletedMsg) {
404         if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
405         sendMessage(DataConnection.EVENT_DISCONNECT_ALL,
406                 new DisconnectParams(null, reason, onCompletedMsg));
407     }
408 
409     /**
410      * @return connection id
411      */
getDataConnectionIdSync()412     public int getDataConnectionIdSync() {
413         // Safe because this is owned by the caller.
414         return mDc.getDataConnectionId();
415     }
416 
417     @Override
toString()418     public String toString() {
419         return mDc.getName();
420     }
421 
isCallerOnDifferentThread()422     private boolean isCallerOnDifferentThread() {
423         long curThreadId = Thread.currentThread().getId();
424         boolean value = mDcThreadId != curThreadId;
425         if (DBG) log("isCallerOnDifferentThread: " + value);
426         return value;
427     }
428 
log(String s)429     private void log(String s) {
430         android.telephony.Rlog.d(mLogTag, "DataConnectionAc " + s);
431     }
432 
getPcscfAddr()433     public String[] getPcscfAddr() {
434         return mDc.mPcscfAddr;
435     }
436 }
437