Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de39b267 authored by Malcolm Chen's avatar Malcolm Chen Committed by android-build-merger
Browse files

Merge "Add NetworkRegistrationManager." am: 051e5ee1

am: 1a68ac2a

Change-Id: Ifab420540f904b3b311b3f013bc40a45a0ecc302
parents d5804e61 1a68ac2a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -305,6 +305,7 @@ public class CellularNetworkService extends NetworkService {
            return result;
        }

        @Override
        public void getNetworkRegistrationState(int domain, NetworkServiceCallback callback) {
            if (DBG) log("getNetworkRegistrationState for domain " + domain);
            Message message = null;
+230 −0
Original line number Diff line number Diff line
/*
 * 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 com.android.internal.telephony;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.RemoteException;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.CarrierConfigManager;
import android.telephony.INetworkService;
import android.telephony.INetworkServiceCallback;
import android.telephony.NetworkRegistrationState;
import android.telephony.NetworkService;
import android.telephony.Rlog;

/**
 * Class that serves as the layer between NetworkService and ServiceStateTracker. It helps binding,
 * sending request and registering for state change to NetworkService.
 */
public class NetworkRegistrationManager {
    private static final String TAG = NetworkRegistrationManager.class.getSimpleName();

    private final int mTransportType;

    private final Phone mPhone;

    private final CarrierConfigManager mCarrierConfigManager;

    // Registrants who listens registration state change callback from this class.
    private final RegistrantList mRegStateChangeRegistrants = new RegistrantList();

    private INetworkService.Stub mServiceBinder;

    private RegManagerDeathRecipient mDeathRecipient;

    public NetworkRegistrationManager(int transportType, Phone phone) {
        mTransportType = transportType;
        mPhone = phone;
        mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService(
                Context.CARRIER_CONFIG_SERVICE);

        bindService();
    }

    public boolean isServiceConnected() {
        return (mServiceBinder != null) && (mServiceBinder.isBinderAlive());
    }

    public void unregisterForNetworkRegistrationStateChanged(Handler h) {
        mRegStateChangeRegistrants.remove(h);
    }

    public void registerForNetworkRegistrationStateChanged(Handler h, int what, Object obj) {
        logd("registerForNetworkRegistrationStateChanged");
        Registrant r = new Registrant(h, what, obj);
        mRegStateChangeRegistrants.addUnique(h, what, obj);
    }

    public void getNetworkRegistrationState(int domain, Message onCompleteMessage) {
        if (onCompleteMessage == null) return;

        logd("getNetworkRegistrationState domain " + domain);
        if (!isServiceConnected()) {
            onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj, null,
                    new IllegalStateException("Service not connected."));
            onCompleteMessage.sendToTarget();
            return;
        }

        try {
            mServiceBinder.getNetworkRegistrationState(mPhone.getPhoneId(), domain,
                    new NetworkRegStateCallback(onCompleteMessage));
        } catch (RemoteException e) {
            Rlog.e(TAG, "getNetworkRegistrationState RemoteException " + e);
            onCompleteMessage.obj = new AsyncResult(onCompleteMessage.obj, null, e);
            onCompleteMessage.sendToTarget();
        }
    }

    private class RegManagerDeathRecipient implements IBinder.DeathRecipient {

        private final ComponentName mComponentName;

        RegManagerDeathRecipient(ComponentName name) {
            mComponentName = name;
        }

        @Override
        public void binderDied() {
            // TODO: try to restart the service.
            logd("NetworkService(" + mComponentName +  " transport type "
                    + mTransportType + ") died.");
        }
    }

    private class NetworkServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mServiceBinder = (INetworkService.Stub) service;
            mDeathRecipient = new RegManagerDeathRecipient(name);
            try {
                mServiceBinder.linkToDeath(mDeathRecipient, 0);
                mServiceBinder.createNetworkServiceProvider(mPhone.getPhoneId());
                mServiceBinder.registerForNetworkRegistrationStateChanged(mPhone.getPhoneId(),
                        new NetworkRegStateCallback(null));
            } catch (RemoteException exception) {
                // Remote exception means that the binder already died.
                mDeathRecipient.binderDied();
                logd("RemoteException " + exception);
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            logd("onServiceDisconnected " + name);
            if (mServiceBinder != null) {
                mServiceBinder.unlinkToDeath(mDeathRecipient, 0);
            }
        }
    }

    private class NetworkRegStateCallback extends INetworkServiceCallback.Stub {
        // Message only used upon onGetNetworkRegistrationStateComplete.
        // If the callback is passed to listen to network state change,
        // this message is null.
        private final Message mOnCompleteMessage;

        NetworkRegStateCallback(Message onCompleteMessage) {
            mOnCompleteMessage = onCompleteMessage;
        }

        @Override
        public void onGetNetworkRegistrationStateComplete(
                int result, NetworkRegistrationState state) {
            logd("onGetNetworkRegistrationStateComplete result "
                    + result + " state " + state);
            mOnCompleteMessage.arg1 = result;
            mOnCompleteMessage.obj = new AsyncResult(mOnCompleteMessage.obj, state, null);
            mOnCompleteMessage.sendToTarget();
        }

        @Override
        public void onNetworkStateChanged() {
            logd("onNetworkStateChanged");
            mRegStateChangeRegistrants.notifyRegistrants();
        }
    }

    private boolean bindService() {
        Intent intent = new Intent(NetworkService.NETWORK_SERVICE_INTERFACE);
        intent.setPackage(getPackageName());
        try {
            // We bind this as a foreground service because it is operating directly on the SIM,
            // and we do not want it subjected to power-savings restrictions while doing so.
            return mPhone.getContext().bindService(intent, new NetworkServiceConnection(),
                    Context.BIND_AUTO_CREATE);
        } catch (SecurityException e) {
            loge("bindService failed " + e);
            return false;
        }
    }

    private String getPackageName() {
        String packageName;
        int resourceId;
        String carrierConfig;

        switch (mTransportType) {
            case TransportType.WWAN:
                resourceId = com.android.internal.R.string.config_wwan_network_service_package;
                carrierConfig = CarrierConfigManager
                        .KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING;
                break;
            case TransportType.WLAN:
                resourceId = com.android.internal.R.string.config_wlan_network_service_package;
                carrierConfig = CarrierConfigManager
                        .KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING;
                break;
            default:
                throw new IllegalStateException("Transport type not WWAN or WLAN. type="
                        + mTransportType);
        }

        // Read package name from resource overlay
        packageName = mPhone.getContext().getResources().getString(resourceId);

        PersistableBundle b = mCarrierConfigManager.getConfigForSubId(mPhone.getSubId());

        if (b != null) {
            // If carrier config overrides it, use the one from carrier config
            packageName = b.getString(carrierConfig, packageName);
        }

        logd("Binding to packageName " + packageName + " for transport type"
                + mTransportType);

        return packageName;
    }

    private static int logd(String msg) {
        return Rlog.d(TAG, msg);
    }

    private static int loge(String msg) {
        return Rlog.e(TAG, msg);
    }
}