/* * Copyright 2017 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; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; 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.NetworkRegistrationInfo.Domain; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.telephony.Rlog; import java.util.ArrayList; import java.util.List; /** * Base class of network service. Services that extend NetworkService must register the service in * their AndroidManifest to be detected by the framework. They must be protected by the permission * "android.permission.BIND_TELEPHONY_NETWORK_SERVICE". The network service definition in the * manifest must follow the following format: * ... * * * * * * @hide */ @SystemApi public abstract class NetworkService extends Service { private final String TAG = NetworkService.class.getSimpleName(); @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String SERVICE_INTERFACE = "android.telephony.NetworkService"; private static final int NETWORK_SERVICE_CREATE_NETWORK_SERVICE_PROVIDER = 1; private static final int NETWORK_SERVICE_REMOVE_NETWORK_SERVICE_PROVIDER = 2; private static final int NETWORK_SERVICE_REMOVE_ALL_NETWORK_SERVICE_PROVIDERS = 3; private static final int NETWORK_SERVICE_GET_REGISTRATION_INFO = 4; private static final int NETWORK_SERVICE_REGISTER_FOR_INFO_CHANGE = 5; private static final int NETWORK_SERVICE_UNREGISTER_FOR_INFO_CHANGE = 6; private static final int NETWORK_SERVICE_INDICATION_NETWORK_INFO_CHANGED = 7; private final HandlerThread mHandlerThread; private final NetworkServiceHandler mHandler; private final SparseArray mServiceMap = new SparseArray<>(); /** * @hide */ @VisibleForTesting public final INetworkServiceWrapper mBinder = new INetworkServiceWrapper(); /** * The abstract class of the actual network service implementation. The network service provider * must extend this class to support network connection. Note that each instance of network * service is associated with one physical SIM slot. */ public abstract class NetworkServiceProvider implements AutoCloseable { private final int mSlotIndex; private final List mNetworkRegistrationInfoChangedCallbacks = new ArrayList<>(); /** * Constructor * @param slotIndex SIM slot id the data service provider associated with. */ public NetworkServiceProvider(int slotIndex) { mSlotIndex = slotIndex; } /** * @return SIM slot index the network service associated with. */ public final int getSlotIndex() { return mSlotIndex; } /** * Request network registration info. The result will be passed to the callback. * * @param domain Network domain * @param callback The callback for reporting network registration info */ public void requestNetworkRegistrationInfo(@Domain int domain, @NonNull NetworkServiceCallback callback) { callback.onRequestNetworkRegistrationInfoComplete( NetworkServiceCallback.RESULT_ERROR_UNSUPPORTED, null); } /** * Notify the system that network registration info is changed. */ public final void notifyNetworkRegistrationInfoChanged() { mHandler.obtainMessage(NETWORK_SERVICE_INDICATION_NETWORK_INFO_CHANGED, mSlotIndex, 0, null).sendToTarget(); } private void registerForInfoChanged(@NonNull INetworkServiceCallback callback) { synchronized (mNetworkRegistrationInfoChangedCallbacks) { mNetworkRegistrationInfoChangedCallbacks.add(callback); } } private void unregisterForInfoChanged(@NonNull INetworkServiceCallback callback) { synchronized (mNetworkRegistrationInfoChangedCallbacks) { mNetworkRegistrationInfoChangedCallbacks.remove(callback); } } private void notifyInfoChangedToCallbacks() { for (INetworkServiceCallback callback : mNetworkRegistrationInfoChangedCallbacks) { try { callback.onNetworkStateChanged(); } catch (RemoteException exception) { // Doing nothing. } } } /** * Called when the instance of network service is destroyed (e.g. got unbind or binder died) * or when the network service provider is removed. The extended class should implement this * method to perform cleanup works. */ @Override public abstract void close(); } private class NetworkServiceHandler extends Handler { NetworkServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message message) { final int slotIndex = message.arg1; final INetworkServiceCallback callback = (INetworkServiceCallback) message.obj; NetworkServiceProvider serviceProvider = mServiceMap.get(slotIndex); switch (message.what) { case NETWORK_SERVICE_CREATE_NETWORK_SERVICE_PROVIDER: // If the service provider doesn't exist yet, we try to create it. if (serviceProvider == null) { mServiceMap.put(slotIndex, onCreateNetworkServiceProvider(slotIndex)); } break; case NETWORK_SERVICE_REMOVE_NETWORK_SERVICE_PROVIDER: // If the service provider doesn't exist yet, we try to create it. if (serviceProvider != null) { serviceProvider.close(); mServiceMap.remove(slotIndex); } break; case NETWORK_SERVICE_REMOVE_ALL_NETWORK_SERVICE_PROVIDERS: for (int i = 0; i < mServiceMap.size(); i++) { serviceProvider = mServiceMap.get(i); if (serviceProvider != null) { serviceProvider.close(); } } mServiceMap.clear(); break; case NETWORK_SERVICE_GET_REGISTRATION_INFO: if (serviceProvider == null) break; int domainId = message.arg2; serviceProvider.requestNetworkRegistrationInfo(domainId, new NetworkServiceCallback(callback)); break; case NETWORK_SERVICE_REGISTER_FOR_INFO_CHANGE: if (serviceProvider == null) break; serviceProvider.registerForInfoChanged(callback); break; case NETWORK_SERVICE_UNREGISTER_FOR_INFO_CHANGE: if (serviceProvider == null) break; serviceProvider.unregisterForInfoChanged(callback); break; case NETWORK_SERVICE_INDICATION_NETWORK_INFO_CHANGED: if (serviceProvider == null) break; serviceProvider.notifyInfoChangedToCallbacks(); break; default: break; } } } /** * Default constructor. */ public NetworkService() { mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new NetworkServiceHandler(mHandlerThread.getLooper()); log("network service created"); } /** * Create the instance of {@link NetworkServiceProvider}. Network service provider must override * this method to facilitate the creation of {@link NetworkServiceProvider} instances. The system * will call this method after binding the network service for each active SIM slot id. * * This methead is guaranteed to be invoked in {@link NetworkService}'s internal handler thread * whose looper can be retrieved with {@link Looper.myLooper()} when override this method. * * @param slotIndex SIM slot id the network service associated with. * @return Network service object. Null if failed to create the provider (e.g. invalid slot * index) */ @Nullable public abstract NetworkServiceProvider onCreateNetworkServiceProvider(int slotIndex); @Override public IBinder onBind(Intent intent) { if (intent == null || !SERVICE_INTERFACE.equals(intent.getAction())) { loge("Unexpected intent " + intent); return null; } return mBinder; } @Override public boolean onUnbind(Intent intent) { mHandler.obtainMessage(NETWORK_SERVICE_REMOVE_ALL_NETWORK_SERVICE_PROVIDERS, 0, 0, null).sendToTarget(); return false; } /** @hide */ @Override public void onDestroy() { mHandlerThread.quitSafely(); super.onDestroy(); } /** * A wrapper around INetworkService that forwards calls to implementations of * {@link NetworkService}. */ private class INetworkServiceWrapper extends INetworkService.Stub { @Override public void createNetworkServiceProvider(int slotIndex) { mHandler.obtainMessage(NETWORK_SERVICE_CREATE_NETWORK_SERVICE_PROVIDER, slotIndex, 0, null).sendToTarget(); } @Override public void removeNetworkServiceProvider(int slotIndex) { mHandler.obtainMessage(NETWORK_SERVICE_REMOVE_NETWORK_SERVICE_PROVIDER, slotIndex, 0, null).sendToTarget(); } @Override public void requestNetworkRegistrationInfo(int slotIndex, int domain, INetworkServiceCallback callback) { mHandler.obtainMessage(NETWORK_SERVICE_GET_REGISTRATION_INFO, slotIndex, domain, callback).sendToTarget(); } @Override public void registerForNetworkRegistrationInfoChanged( int slotIndex, INetworkServiceCallback callback) { mHandler.obtainMessage(NETWORK_SERVICE_REGISTER_FOR_INFO_CHANGE, slotIndex, 0, callback).sendToTarget(); } @Override public void unregisterForNetworkRegistrationInfoChanged( int slotIndex, INetworkServiceCallback callback) { mHandler.obtainMessage(NETWORK_SERVICE_UNREGISTER_FOR_INFO_CHANGE, slotIndex, 0, callback).sendToTarget(); } } private final void log(String s) { Rlog.d(TAG, s); } private final void loge(String s) { Rlog.e(TAG, s); } }