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

Commit 19a91def authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove all eSIM Invisible Profiles during FDR" into qt-r1-dev

parents c2dc9d31 e0662471
Loading
Loading
Loading
Loading
+124 −5
Original line number Original line Diff line number Diff line
@@ -32,6 +32,8 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.os.storage.IStorageManager;
import android.os.storage.IStorageManager;
import android.provider.Settings;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.format.DateFormat;
@@ -59,10 +61,12 @@ import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipInputStream;
@@ -90,11 +94,14 @@ public class RecoverySystem {
    private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
    private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;


    private static final long DEFAULT_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 30000L; // 30 s
    private static final long DEFAULT_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 30000L; // 30 s

    private static final long MIN_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 5000L; // 5 s
    private static final long MIN_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 5000L; // 5 s

    private static final long MAX_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 60000L; // 60 s
    private static final long MAX_EUICC_FACTORY_RESET_TIMEOUT_MILLIS = 60000L; // 60 s


    private static final long DEFAULT_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS =
            45000L; // 45 s
    private static final long MIN_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS = 15000L; // 15 s
    private static final long MAX_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS = 90000L; // 90 s

    /** Used to communicate with recovery.  See bootable/recovery/recovery.cpp. */
    /** Used to communicate with recovery.  See bootable/recovery/recovery.cpp. */
    private static final File RECOVERY_DIR = new File("/cache/recovery");
    private static final File RECOVERY_DIR = new File("/cache/recovery");
    private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
    private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
@@ -102,9 +109,14 @@ public class RecoverySystem {
    private static final String LAST_PREFIX = "last_";
    private static final String LAST_PREFIX = "last_";
    private static final String ACTION_EUICC_FACTORY_RESET =
    private static final String ACTION_EUICC_FACTORY_RESET =
            "com.android.internal.action.EUICC_FACTORY_RESET";
            "com.android.internal.action.EUICC_FACTORY_RESET";
    private static final String ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS =
            "com.android.internal.action.EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS";


    /** used in {@link #wipeEuiccData} as package name of callback intent */
    /**
    private static final String PACKAGE_NAME_WIPING_EUICC_DATA_CALLBACK = "android";
     * Used in {@link #wipeEuiccData} & {@link #removeEuiccInvisibleSubs} as package name of
     * callback intent.
     */
    private static final String PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK = "android";


    /**
    /**
     * The recovery image uses this file to identify the location (i.e. blocks)
     * The recovery image uses this file to identify the location (i.e. blocks)
@@ -757,8 +769,11 @@ public class RecoverySystem {
        // Block until the ordered broadcast has completed.
        // Block until the ordered broadcast has completed.
        condition.block();
        condition.block();


        EuiccManager euiccManager = context.getSystemService(EuiccManager.class);
        if (wipeEuicc) {
        if (wipeEuicc) {
            wipeEuiccData(context, PACKAGE_NAME_WIPING_EUICC_DATA_CALLBACK);
            wipeEuiccData(context, PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK);
        } else {
            removeEuiccInvisibleSubs(context, euiccManager);
        }
        }


        String shutdownArg = null;
        String shutdownArg = null;
@@ -854,6 +869,110 @@ public class RecoverySystem {
        return false;
        return false;
    }
    }


    private static void removeEuiccInvisibleSubs(
            Context context, EuiccManager euiccManager) {
        ContentResolver cr = context.getContentResolver();
        if (Settings.Global.getInt(cr, Settings.Global.EUICC_PROVISIONED, 0) == 0) {
            // If the eUICC isn't provisioned, there's no need to remove euicc invisible profiles,
            // as there's nothing to be removed.
            Log.i(TAG, "Skip removing eUICC invisible profiles as it is not provisioned.");
            return;
        } else if (euiccManager == null || !euiccManager.isEnabled()) {
            Log.i(TAG, "Skip removing eUICC invisible profiles as eUICC manager is not available.");
            return;
        }
        SubscriptionManager subscriptionManager =
                context.getSystemService(SubscriptionManager.class);
        List<SubscriptionInfo> availableSubs =
                subscriptionManager.getAvailableSubscriptionInfoList();
        if (availableSubs == null || availableSubs.isEmpty()) {
            Log.i(TAG, "Skip removing eUICC invisible profiles as no available profiles found.");
            return;
        }
        List<SubscriptionInfo> invisibleSubs = new ArrayList<>();
        for (SubscriptionInfo sub : availableSubs) {
            if (sub.isEmbedded() && !subscriptionManager.isSubscriptionVisible(sub)) {
                invisibleSubs.add(sub);
            }
        }
        removeEuiccInvisibleSubs(context, invisibleSubs, euiccManager);
    }

    private static boolean removeEuiccInvisibleSubs(
            Context context, List<SubscriptionInfo> subscriptionInfos, EuiccManager euiccManager) {
        if (subscriptionInfos == null || subscriptionInfos.isEmpty()) {
            Log.i(TAG, "There are no eUICC invisible profiles needed to be removed.");
            return true;
        }
        CountDownLatch removeSubsLatch = new CountDownLatch(subscriptionInfos.size());
        final AtomicInteger removedSubsCount = new AtomicInteger(0);

        BroadcastReceiver removeEuiccSubsReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS.equals(intent.getAction())) {
                    if (getResultCode() != EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
                        int detailedCode = intent.getIntExtra(
                                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0);
                        Log.e(TAG, "Error removing euicc opportunistic profile, Detailed code = "
                                + detailedCode);
                    } else {
                        Log.e(TAG, "Successfully remove euicc opportunistic profile.");
                        removedSubsCount.incrementAndGet();
                    }
                    removeSubsLatch.countDown();
                }
            }
        };

        Intent intent = new Intent(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS);
        intent.setPackage(PACKAGE_NAME_EUICC_DATA_MANAGEMENT_CALLBACK);
        PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser(
                context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM);
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ACTION_EUICC_REMOVE_INVISIBLE_SUBSCRIPTIONS);
        HandlerThread euiccHandlerThread =
                new HandlerThread("euiccRemovingSubsReceiverThread");
        euiccHandlerThread.start();
        Handler euiccHandler = new Handler(euiccHandlerThread.getLooper());
        context.getApplicationContext()
                .registerReceiver(
                        removeEuiccSubsReceiver, intentFilter, null, euiccHandler);
        for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
            Log.i(
                    TAG,
                    "Remove invisible subscription " + subscriptionInfo.getSubscriptionId()
                            + " from card " + subscriptionInfo.getCardId());
            euiccManager.createForCardId(subscriptionInfo.getCardId())
                    .deleteSubscription(subscriptionInfo.getSubscriptionId(), callbackIntent);
        }
        try {
            long waitingTimeMillis = Settings.Global.getLong(
                    context.getContentResolver(),
                    Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
                    DEFAULT_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS);
            if (waitingTimeMillis < MIN_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS) {
                waitingTimeMillis = MIN_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS;
            } else if (waitingTimeMillis > MAX_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS) {
                waitingTimeMillis = MAX_EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS;
            }
            if (!removeSubsLatch.await(waitingTimeMillis, TimeUnit.MILLISECONDS)) {
                Log.e(TAG, "Timeout removing invisible euicc profiles.");
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.e(TAG, "Removing invisible euicc profiles interrupted", e);
            return false;
        } finally {
            context.getApplicationContext().unregisterReceiver(removeEuiccSubsReceiver);
            if (euiccHandlerThread != null) {
                euiccHandlerThread.quit();
            }
        }
        return removedSubsCount.get() == subscriptionInfos.size();
    }

    /** {@hide} */
    /** {@hide} */
    public static void rebootPromptAndWipeUserData(Context context, String reason)
    public static void rebootPromptAndWipeUserData(Context context, String reason)
            throws IOException {
            throws IOException {
+10 −0
Original line number Original line Diff line number Diff line
@@ -13550,6 +13550,16 @@ public final class Settings {
        public static final String LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED =
        public static final String LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED =
                "location_settings_link_to_permissions_enabled";
                "location_settings_link_to_permissions_enabled";
        /**
         * Flag to set the waiting time for removing invisible euicc profiles inside System >
         * Settings.
         * Type: long
         *
         * @hide
         */
        public static final String EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS =
                "euicc_removing_invisible_profiles_timeout_millis";
        /**
        /**
         * Flag to set the waiting time for euicc factory reset inside System > Settings
         * Flag to set the waiting time for euicc factory reset inside System > Settings
         * Type: long
         * Type: long
+1 −0
Original line number Original line Diff line number Diff line
@@ -265,6 +265,7 @@ public class SettingsBackupTest {
                    Settings.Global.EUICC_PROVISIONED,
                    Settings.Global.EUICC_PROVISIONED,
                    Settings.Global.EUICC_SUPPORTED_COUNTRIES,
                    Settings.Global.EUICC_SUPPORTED_COUNTRIES,
                    Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
                    Settings.Global.EUICC_FACTORY_RESET_TIMEOUT_MILLIS,
                    Settings.Global.EUICC_REMOVING_INVISIBLE_PROFILES_TIMEOUT_MILLIS,
                    Settings.Global.FANCY_IME_ANIMATIONS,
                    Settings.Global.FANCY_IME_ANIMATIONS,
                    Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                    Settings.Global.FORCE_ALLOW_ON_EXTERNAL,
                    Settings.Global.FORCED_APP_STANDBY_ENABLED,
                    Settings.Global.FORCED_APP_STANDBY_ENABLED,
+2 −2
Original line number Original line Diff line number Diff line
@@ -2976,10 +2976,10 @@ public class SubscriptionManager {
     * @param info the subscriptionInfo to check against.
     * @param info the subscriptionInfo to check against.
     * @return true if this subscription should be visible to the API caller.
     * @return true if this subscription should be visible to the API caller.
     *
     *
     * @hide
     */
     */
    private boolean isSubscriptionVisible(SubscriptionInfo info) {
    public boolean isSubscriptionVisible(SubscriptionInfo info) {
        if (info == null) return false;
        if (info == null) return false;

        // If subscription is NOT grouped opportunistic subscription, it's visible.
        // If subscription is NOT grouped opportunistic subscription, it's visible.
        if (info.getGroupUuid() == null || !info.isOpportunistic()) return true;
        if (info.getGroupUuid() == null || !info.isOpportunistic()) return true;