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