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

Commit 39d584c4 authored by Jack Yu's avatar Jack Yu
Browse files

Optimized the boot up camping time

Currently the data profiles are only loaded after carrier
config is ready, because the preferred data profile might
have carrier config dependency.

Optimized the data profile loading time by loading the
profiles as soon as SIM is loaded. This will help the
boot up camping time for about 450ms averagely (except
for the very first boot up).

Bug: 268535702
Test: Boot up + basic phone funcationality tests
Test: Boot up time test on cheetah (http://go/bootup-screenshot)
Test: atest DataProfileManagerTest
Test: b/241887354#comment94
Change-Id: Id87fa05361e6b100416268d7251bb4c87b1d55c2
parent f7407c5e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2270,7 +2270,7 @@ public class DataNetworkController extends Handler {
    /** Called when subscription info changed. */
    private void onSubscriptionChanged() {
        if (mSubId != mPhone.getSubId()) {
            log("onDataConfigUpdated: mSubId changed from " + mSubId + " to "
            log("onSubscriptionChanged: mSubId changed from " + mSubId + " to "
                    + mPhone.getSubId());
            if (isImsGracefulTearDownSupported()) {
                if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
+136 −51
Original line number Diff line number Diff line
@@ -19,8 +19,12 @@ package com.android.internal.telephony.data;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.NetworkCapabilities;
@@ -67,6 +71,9 @@ import java.util.stream.Collectors;
public class DataProfileManager extends Handler {
    private static final boolean VDBG = true;

    /** Event for SIM loaded. */
    private static final int EVENT_SIM_LOADED = 1;

    /** Event for APN database changed. */
    private static final int EVENT_APN_DATABASE_CHANGED = 2;

@@ -153,7 +160,60 @@ public class DataProfileManager extends Handler {
        mWwanDataServiceManager = dataServiceManager;
        mDataConfigManager = dataNetworkController.getDataConfigManager();
        mDataProfileManagerCallbacks.add(callback);

        IntentFilter filter = new IntentFilter();
        filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
        mPhone.getContext().registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction().equals(
                        TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) {
                    if (mPhone.getPhoneId() == intent.getIntExtra(
                            CarrierConfigManager.EXTRA_SLOT_INDEX,
                            SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
                        sendMessageAtFrontOfQueue(obtainMessage(EVENT_SIM_LOADED));
                    }
                }
            }
        }, filter, null, mPhone);

        registerAllEvents();
        log("created.");
    }

    /**
     * Called when SIM loaded.
     */
    private void onSimLoaded() {
        // Below is for boot up camping optimization purpose. We do not need to wait until carrier
        // config ready to load the profiles. Although preferred data profile might be affected by
        // the carrier config, that's only for the first time boot up. In that case, the preferred
        // data profile from the db would be empty, and we can wait until carrier config ready to
        // determine the preferred data profile. By just loading the essential profiles when SIM
        // loaded, the boot up camping time is slightly improved.
        //
        // The default (i.e. framework generated) data profiles for enterprise, emergency, and IMS
        // will also be added at that time if they are missing from all profiles.
        log("onSimLoaded: subId=" + mPhone.getSubId());
        if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
            int preferredProfileId = getPreferredDataProfileIdFromDb();
            if (preferredProfileId < 0) {
                // Preferred data profile does not exist. This might be the first time boot up.
                // Deferred until carrier config loaded so we can determine the correct preferred
                // data profile. It is intended to bail out here. If we load all the data profiles
                // without knowing the preferred data profile, we might end up with setting up
                // with the wrong one.
                log("onSimLoaded: Preferred data profile does not exist.");
                return;
            }
            mPreferredDataProfile = getPreferredDataProfileFromDb();
            mPreferredDataProfileSetId = getPreferredDataProfileSetId();
            log("onSimLoaded: mPreferredDataProfileSetId=" + mPreferredDataProfileSetId);

            mAllDataProfiles.clear();
            mAllDataProfiles.addAll(loadDataProfilesFromDatabase());
            log("onSimLoaded: Loaded " + mAllDataProfiles);
        }
    }

    /**
@@ -187,6 +247,9 @@ public class DataProfileManager extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case EVENT_SIM_LOADED:
                onSimLoaded();
                break;
            case EVENT_SIM_REFRESH:
                log("Update data profiles due to SIM refresh.");
                updateDataProfiles(FORCED_UPDATE_IA);
@@ -241,21 +304,21 @@ public class DataProfileManager extends Handler {
        cursor.close();
        return dataProfile;
    }

    /**
     * Update all data profiles, including preferred data profile, and initial attach data profile.
     * Also send those profiles down to the modem if needed.
     * Load all data profiles associated with the current SIM from the database.
     *
     * @param forceUpdateIa If {@code true}, we should always send IA again to modem.
     * @return The loaded profiles. Empty list if not found.
     */
    private void updateDataProfiles(boolean forceUpdateIa) {
    private @NonNull List<DataProfile> loadDataProfilesFromDatabase() {
        log("loadDataProfilesFromDatabase: subId=" + mPhone.getSubId());
        List<DataProfile> profiles = new ArrayList<>();
        if (mDataConfigManager.isConfigCarrierSpecific()) {
        Cursor cursor = mPhone.getContext().getContentResolver().query(
                Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/"
                        + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID);
        if (cursor == null) {
            loge("Cannot access APN database through telephony provider.");
                return;
            return new ArrayList<>();
        }
        boolean isInternetSupported = false;
        while (cursor.moveToNext()) {
@@ -283,8 +346,19 @@ public class DataProfileManager extends Handler {
            reportAnomaly("Carrier doesn't support internet.",
                    "9af73e18-b523-4dc5-adab-363eb6613305");
        }

        return profiles;
    }

    /**
     * Update all data profiles, including preferred data profile, and initial attach data profile.
     * Also send those profiles down to the modem if needed.
     *
     * @param forceUpdateIa If {@code true}, we should always send IA again to modem.
     */
    private void updateDataProfiles(boolean forceUpdateIa) {
        List<DataProfile> profiles = loadDataProfilesFromDatabase();

        // Check if any of the profile already supports ENTERPRISE, if not, check if DPC has
        // configured one and retrieve the same.
        DataProfile dataProfile = profiles.stream()
@@ -416,28 +490,39 @@ public class DataProfileManager extends Handler {
    }

    /**
     * Get the preferred data profile for internet data.
     *
     * @return The preferred data profile.
     * @return The preferred data profile id. {@code -1} if not found.
     */
    private @Nullable DataProfile getPreferredDataProfileFromDb() {
        Cursor cursor = mPhone.getContext().getContentResolver().query(
    private int getPreferredDataProfileIdFromDb() {
        try (Cursor cursor = mPhone.getContext().getContentResolver().query(
                Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI,
                        String.valueOf(mPhone.getSubId())), null, null, null,
                Telephony.Carriers.DEFAULT_SORT_ORDER);
        DataProfile dataProfile = null;
                Telephony.Carriers.DEFAULT_SORT_ORDER)) {
            if (cursor != null) {
                if (cursor.getCount() > 0) {
                    cursor.moveToFirst();
                int apnId = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
                dataProfile = mAllDataProfiles.stream()
                    return cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
                }
            }
        }
        return -1;
    }

    /**
     * Get the preferred data profile for internet data.
     *
     * @return The preferred data profile.
     */
    private @Nullable DataProfile getPreferredDataProfileFromDb() {
        int preferredDataProfileId = getPreferredDataProfileIdFromDb();
        if (preferredDataProfileId < 0) {
            log("getPreferredDataProfileFromDb: null");
            return null;
        }
        DataProfile dataProfile = mAllDataProfiles.stream()
                .filter(dp -> dp.getApnSetting() != null
                                && dp.getApnSetting().getId() == apnId)
                        && dp.getApnSetting().getId() == preferredDataProfileId)
                .findFirst()
                .orElse(null);
            }
            cursor.close();
        }
        log("getPreferredDataProfileFromDb: " + dataProfile);
        return dataProfile;
    }
+30 −1
Original line number Diff line number Diff line
@@ -407,7 +407,7 @@ public class DataProfileManagerTest extends TelephonyTest {

        public void setPreferredApn(String apnName) {
            for (Object apnSetting : mAllApnSettings) {
                if (apnName == ((Object[]) apnSetting)[3]) {
                if (Objects.equals(apnName, ((Object[]) apnSetting)[3])) {
                    mPreferredApnId = (int) ((Object[]) apnSetting)[0];
                    mPreferredApnSet = (int) ((Object[]) apnSetting)[28];
                    logd("mPreferredApnId=" + mPreferredApnId + " ,mPreferredApnSet="
@@ -1124,4 +1124,33 @@ public class DataProfileManagerTest extends TelephonyTest {
        assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                TelephonyManager.NETWORK_TYPE_LTE, false)).isNull();
    }

    @Test
    public void testSimLoaded() {
        mDataProfileManagerUT = new DataProfileManager(mPhone, mDataNetworkController,
                mMockedWwanDataServiceManager, Looper.myLooper(), mDataProfileManagerCallback);

        mDataProfileManagerUT.obtainMessage(1 /* EVENT_SIM_LOADED */).sendToTarget();
        processAllMessages();

        DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                new TelephonyNetworkRequest(new NetworkRequest.Builder()
                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        .build(), mPhone),
                TelephonyManager.NETWORK_TYPE_LTE, false);

        // Because preferred APN is not set, SIM load event will not trigger loading data profiles.
        assertThat(dataProfile).isNull();

        mApnSettingContentProvider.setPreferredApn(GENERAL_PURPOSE_APN);
        mDataProfileManagerUT.obtainMessage(1 /* EVENT_SIM_LOADED */).sendToTarget();
        processAllMessages();

        dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                new TelephonyNetworkRequest(new NetworkRequest.Builder()
                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        .build(), mPhone),
                TelephonyManager.NETWORK_TYPE_LTE, false);
        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
    }
}