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

Commit 5de606b4 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 5262136 from 6fc6f352 to qt-release

Change-Id: I90affc4643f25331f3fba44cd47f6d947b1c2e3d
parents 2abc4bb6 6fc6f352
Loading
Loading
Loading
Loading
+8 −11
Original line number Diff line number Diff line
@@ -40,16 +40,7 @@ java_library {
        "src/java/**/*.logtags",
    ],

    jarjar_rules: ":framework-hidl-jarjar",

    libs: [
        "voip-common",
        "ims-common",
        "services",
    ],
    static_libs: [
        "telephony-protos",
        "ecc-protos-lite",
        "android.hardware.radio-V1.0-java",
        "android.hardware.radio-V1.1-java",
        "android.hardware.radio-V1.2-java",
@@ -59,7 +50,13 @@ java_library {
        "android.hardware.radio.config-V1.1-java",
        "android.hardware.radio.config-V1.2-java",
        "android.hardware.radio.deprecated-V1.0-java",
        "android.hidl.base-V1.0-java",
        "voip-common",
        "ims-common",
        "services",
    ],
    static_libs: [
        "telephony-protos",
        "ecc-protos-lite",
        "android-support-annotations",
    ],

+123 −6
Original line number Diff line number Diff line
@@ -16,21 +16,29 @@

package com.android.internal.telephony;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.provider.Telephony.Sms.Intents;
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;


/**
@@ -44,6 +52,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 +100,46 @@ 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;
    }

    /**
     * Handle an incoming SMS_DELIVER_ACTION intent if it is an app-only SMS.
     */
@@ -102,14 +151,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 +184,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 +221,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 +240,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 +269,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;
        }
    }

+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.util.Base64;
import android.util.Log;

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;

/** Utility class for generating token, i.e., hash of package name and certificate. */
public class PackageBasedTokenUtil {
    private static final String TAG = "PackageBasedTokenUtil";
    private static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8");
    private static final String HASH_TYPE = "SHA-256";
    private static final int NUM_HASHED_BYTES = 9; // 9 bytes = 72 bits = 12 Base64s

    static final int NUM_BASE64_CHARS = 11; // truncate 12 into 11 Base64 chars

    /**
     * Generate token and check collision with other packages.
     */
    public static String generateToken(Context context, String packageName) {
        PackageManager packageManager = context.getPackageManager();
        String token = generatePackageBasedToken(packageManager, packageName);

        // Check for token confliction
        List<PackageInfo> packages =
                packageManager.getInstalledPackages(PackageManager.GET_META_DATA);

        for (PackageInfo packageInfo : packages) {
            String otherPackageName = packageInfo.packageName;
            if (packageName.equals(otherPackageName)) {
                continue;
            }

            String otherToken = generatePackageBasedToken(packageManager, otherPackageName);
            if (token.equals(otherToken)) {
                Log.e(TAG, "token collides with other installed app.");
                token = null;
            }
        }

        return token;
    }

    private static String generatePackageBasedToken(
            PackageManager packageManager, String packageName) {
        String token = null;
        Signature[] signatures;

        try {
            // It is actually a certificate (public key), not a signature.
            signatures = packageManager.getPackageInfo(
                    packageName, PackageManager.GET_SIGNATURES).signatures;
        } catch (NameNotFoundException e) {
            Log.e(TAG, "Failed to find package with package name: " + packageName);
            return token;
        }

        if (signatures == null) {
            Log.e(TAG, "The certificates is missing.");
        } else {
            MessageDigest messageDigest;
            try {
                messageDigest = MessageDigest.getInstance(HASH_TYPE);
            } catch (NoSuchAlgorithmException e) {
                Log.e(TAG, "NoSuchAlgorithmException" + e);
                return null;
            }

            messageDigest.update(packageName.getBytes(CHARSET_UTF_8));
            String space = " ";
            messageDigest.update(space.getBytes(CHARSET_UTF_8));
            for (int i = 0; i < signatures.length; i++) {
                messageDigest.update(signatures[i].toCharsString().getBytes(CHARSET_UTF_8));
            }
            byte[] hashSignatures = messageDigest.digest();
            // truncated into NUM_HASHED_BYTES
            hashSignatures = Arrays.copyOf(hashSignatures, NUM_HASHED_BYTES);
            // encode into Base64
            token = Base64.encodeToString(hashSignatures, Base64.NO_PADDING | Base64.NO_WRAP);
            token = token.substring(0, NUM_BASE64_CHARS);
        }
        return token;
    }
}
+9 −3
Original line number Diff line number Diff line
@@ -2000,8 +2000,6 @@ public class RIL extends BaseCommands implements CommandsInterface {
        IRadio radioProxy = getRadioProxy(result);
        if (radioProxy != null) {
            if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_2)) {
                android.hardware.radio.V1_2.IRadio radioProxy12 =
                        (android.hardware.radio.V1_2.IRadio) radioProxy;

                android.hardware.radio.V1_2.NetworkScanRequest request =
                        new android.hardware.radio.V1_2.NetworkScanRequest();
@@ -2031,7 +2029,15 @@ public class RIL extends BaseCommands implements CommandsInterface {
                }

                try {
                    if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_4)) {
                        android.hardware.radio.V1_4.IRadio radioProxy14 =
                                (android.hardware.radio.V1_4.IRadio) radioProxy;
                        radioProxy14.startNetworkScan_1_4(rr.mSerial, request);
                    } else {
                        android.hardware.radio.V1_2.IRadio radioProxy12 =
                                (android.hardware.radio.V1_2.IRadio) radioProxy;
                        radioProxy12.startNetworkScan_1_2(rr.mSerial, request);
                    }
                } catch (RemoteException | RuntimeException e) {
                    handleRadioProxyExceptionForRR(rr, "startNetworkScan", e);
                }
+10 −0
Original line number Diff line number Diff line
@@ -606,6 +606,16 @@ public class RadioResponse extends IRadioResponse.Stub {
        responseScanStatus(responseInfo);
    }

    /**
     * The same method as startNetworkScanResponse, except disallowing error codes
     * OPERATION_NOT_ALLOWED and REQUEST_NOT_SUPPORTED.
     *
     * @param responseInfo Response info struct containing response type, serial no. and error
     */
    public void startNetworkScanResponse_1_4(RadioResponseInfo responseInfo) {
        responseScanStatus(responseInfo);
    }

    /**
     *
     * @param responseInfo Response info struct containing response type, serial no. and error
Loading