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

Commit 051e5ee1 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add NetworkRegistrationManager."

parents b4a9738e 35941b06
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);
    }
}