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

Commit b61d2373 authored by Xin Li's avatar Xin Li
Browse files

DO NOT MERGE - Merge qt-dev-plus-aosp-without-vendor (5699924) into

stage-aosp-master

Bug: 134405016
Change-Id: Iefc26296b103d7588182c2383dfa5d4180a660a3
parents adc59877 9ad588da
Loading
Loading
Loading
Loading
+34 −2
Original line number Diff line number Diff line
@@ -1608,11 +1608,43 @@ message TelephonyEvent {

    // Group id level 1. Logged only if gid1 is configured from subscription
    // but its matching rule is unknown
    optional string gid1 = 2;
    optional string unknown_gid1 = 2;

    // MCC and MNC that map to this carrier. Logged only if mccmnc is configured
    // from subscription but its matching rule is unknown
    optional string mccmnc = 3;
    optional string unknown_mccmnc = 3;

    // MCC and MNC from the subscription that map to this carrier.
    optional string mccmnc = 4;

    // Group id level 1 from the subscription that map to this carrier.
    optional string gid1 = 5;

    // Group id level 2 from the subscription that map to this carrier.
    optional string gid2 = 6;

    // spn from the subscription that map to this carrier.
    optional string spn = 7;

    // pnn from the subscription that map to this carrier.
    optional string pnn = 8;

    // iccid prefix from the subscription that map to this carrier.
    // only log first 7 outof 20 bit of full iccid
    optional string iccid_prefix = 9;

    // imsi prefix from the subscription that map to this carrier.
    // only log additional 2 bits other than MCC MNC.
    optional string imsi_prefix = 10;

    // Carrier Privilege Access Rule in hex string from the subscription.
    // Sample values: 61ed377e85d386a8dfee6b864bd85b0bfaa5af88
    repeated string privilege_access_rule = 11;

    // The Access Point Name, corresponding to "apn" field returned by
    // "content://telephony/carriers/preferapn" on device.
    // Sample values: fast.t-mobile.com, internet. Note only log if this apn is not user edited.
    optional string preferApn = 12;
  }

  // Time when event happened on device, in milliseconds since epoch
+148 −7
Original line number Diff line number Diff line
@@ -16,25 +16,39 @@

package com.android.internal.telephony;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.role.IRoleManager;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.provider.Telephony.Sms.Intents;
import android.telephony.IFinancialSmsCallback;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Base64;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

import java.security.SecureRandom;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 *  Manager for app specific incoming SMS requests. This can be used to implement SMS based
 *  Manager for app specific SMS requests. This can be used to implement SMS based
 *  communication channels (e.g. for SMS based phone number verification) without needing the
 *  {@link Manifest.permission#RECEIVE_SMS} permission.
 *
@@ -44,6 +58,7 @@ import java.util.Map;
public class AppSmsManager {
    private static final String LOG_TAG = "AppSmsManager";

    private static final long TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(5);
    private final SecureRandom mRandom;
    private final Context mContext;
    private final Object mLock = new Object();
@@ -91,6 +106,64 @@ public class AppSmsManager {
        return token;
    }

    /**
     * Create an app specific incoming SMS request for the the calling package.
     *
     * This method returns a token that if included in a subsequent incoming SMS message the
     * {@link Intents.SMS_RECEIVED_ACTION} intent will be delivered only to the calling package and
     * will not require the application have the {@link Manifest.permission#RECEIVE_SMS} permission.
     *
     * An app can only have one request at a time, if the app already has a request it will be
     * dropped and the new one will be added.
     *
     * @return Token to include in an SMS to have it delivered directly to the app.
     */
    public String createAppSpecificSmsTokenWithPackageInfo(int subId,
            @NonNull String callingPackageName,
            @Nullable String prefixes,
            @NonNull PendingIntent intent) {
        Preconditions.checkStringNotEmpty(callingPackageName,
                "callingPackageName cannot be null or empty.");
        Preconditions.checkNotNull(intent, "intent cannot be null");
        // Check calling uid matches callingpkg.
        AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
        appOps.checkPackage(Binder.getCallingUid(), callingPackageName);

        // Generate a token to store the request under.
        String token = PackageBasedTokenUtil.generateToken(mContext, callingPackageName);
        if (token != null) {
            synchronized (mLock) {
                // Only allow one request in flight from a package.
                if (mPackageMap.containsKey(callingPackageName)) {
                    removeRequestLocked(mPackageMap.get(callingPackageName));
                }
                // Store state.
                AppRequestInfo info = new AppRequestInfo(
                        callingPackageName, intent, token, prefixes, subId, true);
                addRequestLocked(info);
            }
        }
        return token;
    }

    /**
     * Get filtered SMS messages for financial app.
     */
    public void getSmsMessagesForFinancialApp(
            String callingPkg, Bundle params, final IFinancialSmsCallback callback) {
        try {
            IRoleManager roleManager = IRoleManager.Stub.asInterface(
                    ServiceManager.getServiceOrThrow(Context.ROLE_SERVICE));
            roleManager.getSmsMessagesForFinancialApp(callingPkg, params, callback);
        } catch (RemoteException e) {
            Log.e(LOG_TAG, "Receive RemoteException.");
            // do nothing
        } catch (ServiceNotFoundException e) {
            Log.e(LOG_TAG, "Service not found.");
            // do nothing
        }
    }

    /**
     * Handle an incoming SMS_DELIVER_ACTION intent if it is an app-only SMS.
     */
@@ -102,14 +175,27 @@ public class AppSmsManager {
        }

        synchronized (mLock) {
            AppRequestInfo info = findAppRequestInfoSmsIntentLocked(intent);
            removeExpiredTokenLocked();

            String message = extractMessage(intent);
            if (TextUtils.isEmpty(message)) {
                return false;
            }

            AppRequestInfo info = findAppRequestInfoSmsIntentLocked(message);
            if (info == null) {
                // The message didn't contain a token -- nothing to do.
                return false;
            }

            try {
                Intent fillIn = new Intent();
                fillIn.putExtras(intent.getExtras());
                Intent fillIn = new Intent()
                        .putExtras(intent.getExtras())
                        .putExtra(SmsManager.EXTRA_STATUS, SmsManager.RESULT_STATUS_SUCCESS)
                        .putExtra(SmsManager.EXTRA_SMS_MESSAGE, message)
                        .putExtra(SmsManager.EXTRA_SIM_SUBSCRIPTION_ID, info.subId)
                        .addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);

                info.pendingIntent.send(mContext, 0, fillIn);
            } catch (PendingIntent.CanceledException e) {
                // The pending intent is canceled, send this SMS as normal.
@@ -122,7 +208,31 @@ public class AppSmsManager {
        }
    }

    private AppRequestInfo findAppRequestInfoSmsIntentLocked(Intent intent) {
    private void removeExpiredTokenLocked() {
        final long currentTimeMillis = System.currentTimeMillis();

        final Set<String> keySet = mTokenMap.keySet();
        for (String token : keySet) {
            AppRequestInfo request = mTokenMap.get(token);
            if (request.packageBasedToken
                    && (currentTimeMillis - TIMEOUT_MILLIS > request.timestamp)) {
                // Send the provided intent with SMS retriever status
                try {
                    Intent fillIn = new Intent()
                            .putExtra(SmsManager.EXTRA_STATUS,
                                    SmsManager.RESULT_STATUS_TIMEOUT)
                            .addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
                    request.pendingIntent.send(mContext, 0, fillIn);
                } catch (PendingIntent.CanceledException e) {
                    // do nothing
                }

                removeRequestLocked(request);
            }
        }
    }

    private String extractMessage(Intent intent) {
        SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
        if (messages == null) {
            return null;
@@ -135,11 +245,13 @@ public class AppSmsManager {
            fullMessageBuilder.append(message.getMessageBody());
        }

        String fullMessage = fullMessageBuilder.toString();
        return fullMessageBuilder.toString();
    }

    private AppRequestInfo findAppRequestInfoSmsIntentLocked(String fullMessage) {
        // Look for any tokens in the full message.
        for (String token : mTokenMap.keySet()) {
            if (fullMessage.contains(token)) {
            if (fullMessage.trim().contains(token) && hasPrefix(token, fullMessage)) {
                return mTokenMap.get(token);
            }
        }
@@ -152,6 +264,21 @@ public class AppSmsManager {
        return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
    }

    private boolean hasPrefix(String token, String message) {
        AppRequestInfo request = mTokenMap.get(token);
        if (TextUtils.isEmpty(request.prefixes)) {
            return true;
        }

        String[] prefixes = request.prefixes.split(SmsManager.REGEX_PREFIX_DELIMITER);
        for (String prefix : prefixes) {
            if (message.startsWith(prefix)) {
                return true;
            }
        }
        return false;
    }

    private void removeRequestLocked(AppRequestInfo info) {
        mTokenMap.remove(info.token);
        mPackageMap.remove(info.packageName);
@@ -166,11 +293,25 @@ public class AppSmsManager {
        public final String packageName;
        public final PendingIntent pendingIntent;
        public final String token;
        public final long timestamp;
        public final String prefixes;
        public final int subId;
        public final boolean packageBasedToken;

        AppRequestInfo(String packageName, PendingIntent pendingIntent, String token) {
          this(packageName, pendingIntent, token, null,
                  SubscriptionManager.INVALID_SUBSCRIPTION_ID, false);
        }

        AppRequestInfo(String packageName, PendingIntent pendingIntent, String token,
                String prefixes, int subId, boolean packageBasedToken) {
            this.packageName = packageName;
            this.pendingIntent = pendingIntent;
            this.token = token;
            this.timestamp = System.currentTimeMillis();
            this.prefixes = prefixes;
            this.subId = subId;
            this.packageBasedToken = packageBasedToken;
        }
    }

+2 −3
Original line number Diff line number Diff line
@@ -846,12 +846,11 @@ public abstract class BaseCommands implements CommandsInterface {
     *
     * RadioState has 3 values : RADIO_OFF, RADIO_UNAVAILABLE, RADIO_ON.
     *
     * @param newState new radio power state decoded from RIL_UNSOL_RADIO_STATE_CHANGED
     * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED
     * @param forceNotifyRegistrants boolean indicating if registrants should be notified even if
     * there is no change in state
     */
    protected void setRadioState(@TelephonyManager.RadioPowerState int newState,
                                 boolean forceNotifyRegistrants) {
    protected void setRadioState(int newState, boolean forceNotifyRegistrants) {
        int oldState;

        synchronized (mStateMonitor) {
+48 −20
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.internal.telephony;

import static android.preference.PreferenceManager.getDefaultSharedPreferences;
import static android.telephony.CarrierConfigManager.KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL;

import static java.nio.charset.StandardCharsets.UTF_8;

@@ -30,6 +31,8 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ImsiEncryptionInfo;
@@ -64,7 +67,7 @@ import java.util.zip.GZIPInputStream;
 * This class contains logic to get Certificates and keep them current.
 * The class will be instantiated by various Phone implementations.
 */
public class CarrierKeyDownloadManager {
public class CarrierKeyDownloadManager extends Handler {
    private static final String LOG_TAG = "CarrierKeyDownloadManager";

    private static final String MCC_MNC_PREF_TAG = "CARRIER_KEY_DM_MCC_MNC";
@@ -93,8 +96,6 @@ public class CarrierKeyDownloadManager {
    private static final String SEPARATOR = ":";

    private static final String JSON_CERTIFICATE = "certificate";
    // This is a hack to accommodate certain Carriers who insists on using the public-key
    // field to store the certificate. We'll just use which-ever is not null.
    private static final String JSON_CERTIFICATE_ALTERNATE = "public-key";
    private static final String JSON_TYPE = "key-type";
    private static final String JSON_IDENTIFIER = "key-identifier";
@@ -102,15 +103,18 @@ public class CarrierKeyDownloadManager {
    private static final String JSON_TYPE_VALUE_WLAN = "WLAN";
    private static final String JSON_TYPE_VALUE_EPDG = "EPDG";

    private static final int EVENT_ALARM_OR_CONFIG_CHANGE = 0;
    private static final int EVENT_DOWNLOAD_COMPLETE = 1;


    private static final int[] CARRIER_KEY_TYPES = {TelephonyManager.KEY_TYPE_EPDG,
            TelephonyManager.KEY_TYPE_WLAN};
    private static final int UNINITIALIZED_KEY_TYPE = -1;

    private final Phone mPhone;
    private final Context mContext;
    public final DownloadManager mDownloadManager;
    private String mURL;
    private boolean mAllowedOverMeteredNetwork = false;

    public CarrierKeyDownloadManager(Phone phone) {
        mPhone = phone;
@@ -131,31 +135,43 @@ public class CarrierKeyDownloadManager {
            int slotId = mPhone.getPhoneId();
            if (action.equals(INTENT_KEY_RENEWAL_ALARM_PREFIX + slotId)) {
                Log.d(LOG_TAG, "Handling key renewal alarm: " + action);
                handleAlarmOrConfigChange();
                sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
            } else if (action.equals(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD)) {
                if (slotId == intent.getIntExtra(PhoneConstants.PHONE_KEY,
                        SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
                    Log.d(LOG_TAG, "Handling reset intent: " + action);
                    handleAlarmOrConfigChange();
                    sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
                }
            } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
                if (slotId == intent.getIntExtra(PhoneConstants.PHONE_KEY,
                        SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
                    Log.d(LOG_TAG, "Carrier Config changed: " + action);
                    handleAlarmOrConfigChange();
                    sendEmptyMessage(EVENT_ALARM_OR_CONFIG_CHANGE);
                }
            } else if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                Log.d(LOG_TAG, "Download Complete");
                long carrierKeyDownloadIdentifier =
                        intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
                sendMessage(obtainMessage(EVENT_DOWNLOAD_COMPLETE,
                        intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0)));
            }
        }
    };

    @Override
    public void handleMessage (Message msg) {
        switch (msg.what) {
            case EVENT_ALARM_OR_CONFIG_CHANGE:
                handleAlarmOrConfigChange();
                break;
            case EVENT_DOWNLOAD_COMPLETE:
                long carrierKeyDownloadIdentifier = (long) msg.obj;
                String mccMnc = getMccMncSetFromPref();
                if (isValidDownload(mccMnc)) {
                    onDownloadComplete(carrierKeyDownloadIdentifier, mccMnc);
                    onPostDownloadProcessing(carrierKeyDownloadIdentifier);
                }
                break;
        }
    }
    };

    private void onPostDownloadProcessing(long carrierKeyDownloadIdentifier) {
        resetRenewalAlarm();
@@ -370,6 +386,8 @@ public class CarrierKeyDownloadManager {
        }
        mKeyAvailability = b.getInt(CarrierConfigManager.IMSI_KEY_AVAILABILITY_INT);
        mURL = b.getString(CarrierConfigManager.IMSI_KEY_DOWNLOAD_URL_STRING);
        mAllowedOverMeteredNetwork = b.getBoolean(
                KEY_ALLOW_METERED_NETWORK_FOR_CERT_DOWNLOAD_BOOL);
        if (TextUtils.isEmpty(mURL) || mKeyAvailability == 0) {
            Log.d(LOG_TAG, "Carrier not enabled or invalid values");
            return false;
@@ -430,20 +448,27 @@ public class CarrierKeyDownloadManager {
            JSONArray keys = jsonObj.getJSONArray(JSON_CARRIER_KEYS);
            for (int i = 0; i < keys.length(); i++) {
                JSONObject key = keys.getJSONObject(i);
                // This is a hack to accommodate certain carriers who insist on using the public-key
                // field to store the certificate. We'll just use which-ever is not null.
                // Support both "public-key" and "certificate" String property.
                // "certificate" is a more accurate description, however, the 3GPP draft spec
                // S3-170116, "Privacy Protection for EAP-AKA" section 4.3 mandates the use of
                // "public-key".
                String cert = null;
                if (key.has(JSON_CERTIFICATE)) {
                    cert = key.getString(JSON_CERTIFICATE);
                } else {
                    cert = key.getString(JSON_CERTIFICATE_ALTERNATE);
                }
                // The 3GPP draft spec 3GPP draft spec S3-170116, "Privacy Protection for EAP-AKA"
                // section 4.3, does not specify any key-type property. To be compatible with these
                // networks, the logic defaults to WLAN type if not specified.
                int type = TelephonyManager.KEY_TYPE_WLAN;
                if (key.has(JSON_TYPE)) {
                    String typeString = key.getString(JSON_TYPE);
                int type = UNINITIALIZED_KEY_TYPE;
                if (typeString.equals(JSON_TYPE_VALUE_WLAN)) {
                    type = TelephonyManager.KEY_TYPE_WLAN;
                } else if (typeString.equals(JSON_TYPE_VALUE_EPDG)) {
                    if (typeString.equals(JSON_TYPE_VALUE_EPDG)) {
                        type = TelephonyManager.KEY_TYPE_EPDG;
                    } else if (!typeString.equals(JSON_TYPE_VALUE_WLAN)) {
                        Log.e(LOG_TAG, "Invalid key-type specified: " + typeString);
                    }
                }
                String identifier = key.getString(JSON_IDENTIFIER);
                ByteArrayInputStream inStream = new ByteArrayInputStream(cert.getBytes());
@@ -520,7 +545,10 @@ public class CarrierKeyDownloadManager {
        }
        try {
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(mURL));
            request.setAllowedOverMetered(false);

            // TODO(b/128550341): Implement the logic to minimize using metered network such as
            // LTE for downloading a certificate.
            request.setAllowedOverMetered(mAllowedOverMeteredNetwork);
            request.setVisibleInDownloadsUi(false);
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
            Long carrierKeyDownloadRequestId = mDownloadManager.enqueue(request);
+187 −103

File changed.

Preview size limit exceeded, changes collapsed.

Loading