summaryrefslogtreecommitdiff
path: root/telephony/java/android/telephony/data/QualifiedNetworksService.java
blob: 0e1751d50949464267b6ef6ca63d0ec85ececaf8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.telephony.data;

import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.Rlog;
import android.telephony.data.ApnSetting.ApnType;
import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;

import java.util.List;

/**
 * Base class of the qualified networks service, which is a vendor service providing up-to-date
 * qualified network information to the frameworks for data handover control. A qualified network
 * is defined as an access network that is ready for bringing up data connection for given APN
 * types.
 *
 * Services that extend QualifiedNetworksService must register the service in their AndroidManifest
 * to be detected by the framework. They must be protected by the permission
 * "android.permission.BIND_TELEPHONY_DATA_SERVICE". The qualified networks service definition in
 * the manifest must follow the following format:
 * ...
 * <service android:name=".xxxQualifiedNetworksService"
 *     android:permission="android.permission.BIND_TELEPHONY_DATA_SERVICE" >
 *     <intent-filter>
 *         <action android:name="android.telephony.data.QualifiedNetworksService" />
 *     </intent-filter>
 * </service>
 * @hide
 */
@SystemApi
public abstract class QualifiedNetworksService extends Service {
    private static final String TAG = QualifiedNetworksService.class.getSimpleName();

    public static final String QUALIFIED_NETWORKS_SERVICE_INTERFACE =
            "android.telephony.data.QualifiedNetworksService";

    private static final int QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER               = 1;
    private static final int QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER               = 2;
    private static final int QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS          = 3;
    private static final int QNS_UPDATE_QUALIFIED_NETWORKS                          = 4;

    private final HandlerThread mHandlerThread;

    private final QualifiedNetworksServiceHandler mHandler;

    private final SparseArray<NetworkAvailabilityProvider> mProviders = new SparseArray<>();

    /** @hide */
    @VisibleForTesting
    public final IQualifiedNetworksServiceWrapper mBinder = new IQualifiedNetworksServiceWrapper();

    /**
     * The abstract class of the network availability provider implementation. The vendor qualified
     * network service must extend this class to report the available networks for data
     * connection setup. Note that each instance of network availability provider is associated with
     * one physical SIM slot.
     */
    public abstract class NetworkAvailabilityProvider implements AutoCloseable {
        private final int mSlotIndex;

        private IQualifiedNetworksServiceCallback mCallback;

        /**
         * Qualified networks for each APN type. Key is the {@link ApnType}, value is the array
         * of available networks.
         */
        private SparseArray<int[]> mQualifiedNetworkTypesList = new SparseArray<>();

        /**
         * Constructor
         * @param slotIndex SIM slot index the network availability provider associated with.
         */
        public NetworkAvailabilityProvider(int slotIndex) {
            mSlotIndex = slotIndex;
        }

        /**
         * @return SIM slot index the network availability provider associated with.
         */
        public final int getSlotIndex() {
            return mSlotIndex;
        }

        private void registerForQualifiedNetworkTypesChanged(
                IQualifiedNetworksServiceCallback callback) {
            mCallback = callback;

            // Force sending the qualified networks upon registered.
            if (mCallback != null) {
                for (int i = 0; i < mQualifiedNetworkTypesList.size(); i++) {
                    try {
                        mCallback.onQualifiedNetworkTypesChanged(
                                mQualifiedNetworkTypesList.keyAt(i),
                                mQualifiedNetworkTypesList.valueAt(i));
                    } catch (RemoteException e) {
                        loge("Failed to call onQualifiedNetworksChanged. " + e);
                    }
                }
            }
        }

        /**
         * Update the qualified networks list. Network availability provider must invoke this method
         * whenever the qualified networks changes. If this method is never invoked for certain
         * APN types, then frameworks will always use the default (i.e. cellular) data and network
         * service.
         *
         * @param apnTypes APN types of the qualified networks. This must be a bitmask combination
         * of {@link ApnSetting.ApnType}.
         * @param qualifiedNetworkTypes List of network types which are qualified for data
         * connection setup for {@link @apnType} in the preferred order. Each element in the list
         * is a {@link AccessNetworkType}. An empty list indicates no networks are qualified
         * for data setup.
         */
        public final void updateQualifiedNetworkTypes(
                @ApnType int apnTypes, @NonNull List<Integer> qualifiedNetworkTypes) {
            int[] qualifiedNetworkTypesArray =
                    qualifiedNetworkTypes.stream().mapToInt(i->i).toArray();
            mHandler.obtainMessage(QNS_UPDATE_QUALIFIED_NETWORKS, mSlotIndex, apnTypes,
                    qualifiedNetworkTypesArray).sendToTarget();
        }

        private void onUpdateQualifiedNetworkTypes(@ApnType int apnTypes,
                                                   int[] qualifiedNetworkTypes) {
            mQualifiedNetworkTypesList.put(apnTypes, qualifiedNetworkTypes);
            if (mCallback != null) {
                try {
                    mCallback.onQualifiedNetworkTypesChanged(apnTypes, qualifiedNetworkTypes);
                } catch (RemoteException e) {
                    loge("Failed to call onQualifiedNetworksChanged. " + e);
                }
            }
        }

        /**
         * Called when the qualified networks provider is removed. The extended class should
         * implement this method to perform cleanup works.
         */
        @Override
        public abstract void close();
    }

    private class QualifiedNetworksServiceHandler extends Handler {
        QualifiedNetworksServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message message) {
            IQualifiedNetworksServiceCallback callback;
            final int slotIndex = message.arg1;
            NetworkAvailabilityProvider provider = mProviders.get(slotIndex);

            switch (message.what) {
                case QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER:
                    if (mProviders.get(slotIndex) != null) {
                        loge("Network availability provider for slot " + slotIndex
                                + " already existed.");
                        return;
                    }

                    provider = onCreateNetworkAvailabilityProvider(slotIndex);
                    if (provider != null) {
                        mProviders.put(slotIndex, provider);

                        callback = (IQualifiedNetworksServiceCallback) message.obj;
                        provider.registerForQualifiedNetworkTypesChanged(callback);
                    } else {
                        loge("Failed to create network availability provider. slot index = "
                                + slotIndex);
                    }
                    break;

                case QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER:
                    if (provider != null) {
                        provider.close();
                        mProviders.remove(slotIndex);
                    }
                    break;

                case QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS:
                    for (int i = 0; i < mProviders.size(); i++) {
                        provider = mProviders.get(i);
                        if (provider != null) {
                            provider.close();
                        }
                    }
                    mProviders.clear();
                    break;

                case QNS_UPDATE_QUALIFIED_NETWORKS:
                    if (provider == null) break;
                    provider.onUpdateQualifiedNetworkTypes(message.arg2, (int[]) message.obj);
                    break;
            }
        }
    }

    /**
     * Default constructor.
     */
    public QualifiedNetworksService() {
        mHandlerThread = new HandlerThread(TAG);
        mHandlerThread.start();

        mHandler = new QualifiedNetworksServiceHandler(mHandlerThread.getLooper());
        log("Qualified networks service created");
    }

    /**
     * Create the instance of {@link NetworkAvailabilityProvider}. Vendor qualified network service
     * must override this method to facilitate the creation of {@link NetworkAvailabilityProvider}
     * instances. The system will call this method after binding the qualified networks service for
     * each active SIM slot index.
     *
     * @param slotIndex SIM slot index the qualified networks service associated with.
     * @return Qualified networks service instance
     */
    @NonNull
    public abstract NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int slotIndex);

    /** @hide */
    @Override
    public IBinder onBind(Intent intent) {
        if (intent == null || !QUALIFIED_NETWORKS_SERVICE_INTERFACE.equals(intent.getAction())) {
            loge("Unexpected intent " + intent);
            return null;
        }
        return mBinder;
    }

    /** @hide */
    @Override
    public boolean onUnbind(Intent intent) {
        mHandler.obtainMessage(QNS_REMOVE_ALL_NETWORK_AVAILABILITY_PROVIDERS).sendToTarget();
        return false;
    }

    /** @hide */
    @Override
    public void onDestroy() {
        mHandlerThread.quit();
    }

    /**
     * A wrapper around IQualifiedNetworksService that forwards calls to implementations of
     * {@link QualifiedNetworksService}.
     */
    private class IQualifiedNetworksServiceWrapper extends IQualifiedNetworksService.Stub {
        @Override
        public void createNetworkAvailabilityProvider(int slotIndex,
                                                      IQualifiedNetworksServiceCallback callback) {
            mHandler.obtainMessage(QNS_CREATE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0,
                    callback).sendToTarget();
        }

        @Override
        public void removeNetworkAvailabilityProvider(int slotIndex) {
            mHandler.obtainMessage(QNS_REMOVE_NETWORK_AVAILABILITY_PROVIDER, slotIndex, 0)
                    .sendToTarget();
        }
    }

    private void log(String s) {
        Rlog.d(TAG, s);
    }

    private void loge(String s) {
        Rlog.e(TAG, s);
    }
}