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

Unverified Commit 010d27ff authored by Kevin F. Haggerty's avatar Kevin F. Haggerty
Browse files

Merge tag 'android-security-11.0.0_r61' of...

Merge tag 'android-security-11.0.0_r61' of https://android.googlesource.com/platform/frameworks/base into staging/lineage-18.1_merge_android-security-11.0.0_r61

Android security 11.0.0 release 61

* tag 'android-security-11.0.0_r61' of https://android.googlesource.com/platform/frameworks/base:
  [DO NOT MERGE] Do not dismiss keyguard after SIM PUK unlock
  DO NOT MERGE Move accountname and typeName length check from Account.java to AccountManagerService.
  Prevent apps from spamming addAccountExplicitly. See comment here for the discussion on solution https://b.corp.google.com/issues/169762606#comment14
  Fix system zen rules by using owner package name if caller is system
  [RESTRICT AUTOMERGE] Check permission for VoiceInteraction
  Trim any long string inputs that come in to AutomaticZenRule
  Check rule package name in ZenModeHelper.addAutomaticRule
  DO NOT MERGE Fix auto-grant of AR runtime permission if device is upgrading from pre-Q
  Do not send AccessibilityEvent if notification is for different user.
  [RESTRICT AUTOMERGE] Do not send new Intent to non-exported activity when navigateUpTo
  switch TelecomManager List getters to ParceledListSlice
  DO NOT MERGE Move accountname and typeName length check from Account.java to AccountManagerService.

Conflicts:
	services/core/java/com/android/server/pm/permission/PermissionManagerService.java

Change-Id: Ib35acb1b73ecab5019a49da7281113716f25f20d
parents 8a4acc6b 2126b5a0
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.util.Log;

import com.android.internal.annotations.GuardedBy;

import java.util.Objects;
import java.util.Set;

/**
@@ -86,12 +85,6 @@ public class Account implements Parcelable {
        if (TextUtils.isEmpty(type)) {
            throw new IllegalArgumentException("the type must not be empty: " + type);
        }
        if (name.length() > 200) {
            throw new IllegalArgumentException("account name is longer than 200 characters");
        }
        if (type.length() > 200) {
            throw new IllegalArgumentException("account type is longer than 200 characters");
        }
        this.name = name;
        this.type = type;
        this.accessId = accessId;
+48 −10
Original line number Diff line number Diff line
@@ -47,6 +47,13 @@ public final class AutomaticZenRule implements Parcelable {
    private boolean mModified = false;
    private String mPkg;

    /**
     * The maximum string length for any string contained in this automatic zen rule. This pertains
     * both to fields in the rule itself (such as its name) and items with sub-fields.
     * @hide
     */
    public static final int MAX_STRING_LENGTH = 1000;

    /**
     * Creates an automatic zen rule.
     *
@@ -93,10 +100,10 @@ public final class AutomaticZenRule implements Parcelable {
    public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner,
            @Nullable ComponentName configurationActivity, @NonNull Uri conditionId,
            @Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) {
        this.name = name;
        this.owner = owner;
        this.configurationActivity = configurationActivity;
        this.conditionId = conditionId;
        this.name = getTrimmedString(name);
        this.owner = getTrimmedComponentName(owner);
        this.configurationActivity = getTrimmedComponentName(configurationActivity);
        this.conditionId = getTrimmedUri(conditionId);
        this.interruptionFilter = interruptionFilter;
        this.enabled = enabled;
        this.mZenPolicy = policy;
@@ -115,12 +122,12 @@ public final class AutomaticZenRule implements Parcelable {
    public AutomaticZenRule(Parcel source) {
        enabled = source.readInt() == ENABLED;
        if (source.readInt() == ENABLED) {
            name = source.readString();
            name = getTrimmedString(source.readString());
        }
        interruptionFilter = source.readInt();
        conditionId = source.readParcelable(null);
        owner = source.readParcelable(null);
        configurationActivity = source.readParcelable(null);
        owner = getTrimmedComponentName(source.readParcelable(null));
        configurationActivity = getTrimmedComponentName(source.readParcelable(null));
        creationTime = source.readLong();
        mZenPolicy = source.readParcelable(null);
        mModified = source.readInt() == ENABLED;
@@ -196,7 +203,7 @@ public final class AutomaticZenRule implements Parcelable {
     * Sets the representation of the state that causes this rule to become active.
     */
    public void setConditionId(Uri conditionId) {
        this.conditionId = conditionId;
        this.conditionId = getTrimmedUri(conditionId);
    }

    /**
@@ -211,7 +218,7 @@ public final class AutomaticZenRule implements Parcelable {
     * Sets the name of this rule.
     */
    public void setName(String name) {
        this.name = name;
        this.name = getTrimmedString(name);
    }

    /**
@@ -243,7 +250,7 @@ public final class AutomaticZenRule implements Parcelable {
     * that are not backed by {@link android.service.notification.ConditionProviderService}.
     */
    public void setConfigurationActivity(@Nullable ComponentName componentName) {
        this.configurationActivity = componentName;
        this.configurationActivity = getTrimmedComponentName(componentName);
    }

    /**
@@ -333,4 +340,35 @@ public final class AutomaticZenRule implements Parcelable {
            return new AutomaticZenRule[size];
        }
    };

    /**
     * If the package or class name of the provided ComponentName are longer than MAX_STRING_LENGTH,
     * return a trimmed version that truncates each of the package and class name at the max length.
     */
    private static ComponentName getTrimmedComponentName(ComponentName cn) {
        if (cn == null) return null;
        return new ComponentName(getTrimmedString(cn.getPackageName()),
                getTrimmedString(cn.getClassName()));
    }

    /**
     * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
     */
    private static String getTrimmedString(String input) {
        if (input != null && input.length() > MAX_STRING_LENGTH) {
            return input.substring(0, MAX_STRING_LENGTH);
        }
        return input;
    }

    /**
     * Returns a truncated copy of the Uri by trimming the string representation to the maximum
     * string length.
     */
    private static Uri getTrimmedUri(Uri input) {
        if (input != null && input.toString().length() > MAX_STRING_LENGTH) {
            return Uri.parse(getTrimmedString(input.toString()));
        }
        return input;
    }
}
+54 −3
Original line number Diff line number Diff line
@@ -16,12 +16,14 @@

package android.service.voice;

import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.hardware.soundtrigger.KeyphraseMetadata;
@@ -232,8 +234,10 @@ public class AlwaysOnHotwordDetector {
    private final Callback mExternalCallback;
    private final Object mLock = new Object();
    private final Handler mHandler;
    private final Context mContext;

    private int mAvailability = STATE_NOT_READY;
    private boolean mIsGrantedHotwordPermission;

    /**
     *  A ModelParamRange is a representation of supported parameter range for a
@@ -408,23 +412,37 @@ public class AlwaysOnHotwordDetector {
        public abstract void onRecognitionResumed();
    }

    private static boolean hasHotwordPermission(Context context) {
        return context.checkSelfPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
                == PackageManager.PERMISSION_GRANTED;
    }

    private static boolean hasRecordAudioPermission(Context context) {
        return context.checkSelfPermission(Manifest.permission.RECORD_AUDIO)
                == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * @param context The context to check permission
     * @param text The keyphrase text to get the detector for.
     * @param locale The java locale for the detector.
     * @param callback A non-null Callback for receiving the recognition events.
     * @param keyphraseEnrollmentInfo The Enrollment info of key phrase
     * @param modelManagementService A service that allows management of sound models.
     * @hide
     */
    public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
    public AlwaysOnHotwordDetector(Context context, String text, Locale locale, Callback callback,
            KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
            IVoiceInteractionManagerService modelManagementService) {
        mText = text;
        mContext = context;
        mLocale = locale;
        mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
        mExternalCallback = callback;
        mHandler = new MyHandler();
        mInternalCallback = new SoundTriggerListener(mHandler);
        mModelManagementService = modelManagementService;
        mIsGrantedHotwordPermission = hasHotwordPermission(mContext);
        new RefreshAvailabiltyTask().execute();
    }

@@ -477,6 +495,11 @@ public class AlwaysOnHotwordDetector {
    @AudioCapabilities
    public int getSupportedAudioCapabilities() {
        if (DBG) Slog.d(TAG, "getSupportedAudioCapabilities()");

        if (!mIsGrantedHotwordPermission) {
            return 0;
        }

        synchronized (mLock) {
            return getSupportedAudioCapabilitiesLocked();
        }
@@ -515,6 +538,12 @@ public class AlwaysOnHotwordDetector {
     */
    public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
        if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")");

        if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
            throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD "
                    + "permissions to access the detector.");
        }

        synchronized (mLock) {
            if (mAvailability == STATE_INVALID) {
                throw new IllegalStateException("startRecognition called on an invalid detector");
@@ -545,6 +574,12 @@ public class AlwaysOnHotwordDetector {
     */
    public boolean stopRecognition() {
        if (DBG) Slog.d(TAG, "stopRecognition()");

        if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
            throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD "
                    + "permissions to access the detector.");
        }

        synchronized (mLock) {
            if (mAvailability == STATE_INVALID) {
                throw new IllegalStateException("stopRecognition called on an invalid detector");
@@ -582,6 +617,10 @@ public class AlwaysOnHotwordDetector {
            Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")");
        }

        if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
            return SoundTrigger.STATUS_INVALID_OPERATION;
        }

        synchronized (mLock) {
            if (mAvailability == STATE_INVALID) {
                throw new IllegalStateException("setParameter called on an invalid detector");
@@ -609,6 +648,10 @@ public class AlwaysOnHotwordDetector {
            Slog.d(TAG, "getParameter(" + modelParam + ")");
        }

        if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
            return MODEL_PARAM_THRESHOLD_FACTOR;
        }

        synchronized (mLock) {
            if (mAvailability == STATE_INVALID) {
                throw new IllegalStateException("getParameter called on an invalid detector");
@@ -634,6 +677,10 @@ public class AlwaysOnHotwordDetector {
            Slog.d(TAG, "queryParameter(" + modelParam + ")");
        }

        if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
            return null;
        }

        synchronized (mLock) {
            if (mAvailability == STATE_INVALID) {
                throw new IllegalStateException("queryParameter called on an invalid detector");
@@ -742,8 +789,8 @@ public class AlwaysOnHotwordDetector {
     */
    void onSoundModelsChanged() {
        synchronized (mLock) {
            if (mAvailability == STATE_INVALID
                    || mAvailability == STATE_HARDWARE_UNAVAILABLE) {
            if (mAvailability == STATE_INVALID || mAvailability == STATE_HARDWARE_UNAVAILABLE
                    || !hasRecordAudioPermission(mContext)) {
                Slog.w(TAG, "Received onSoundModelsChanged for an unsupported keyphrase/config");
                return;
            }
@@ -962,6 +1009,10 @@ public class AlwaysOnHotwordDetector {
         * @return The initial availability without checking the enrollment status.
         */
        private int internalGetInitialAvailability() {
            if (!mIsGrantedHotwordPermission) {
                return STATE_HARDWARE_UNAVAILABLE;
            }

            synchronized (mLock) {
                // This detector has already been invalidated.
                if (mAvailability == STATE_INVALID) {
+1 −1
Original line number Diff line number Diff line
@@ -318,7 +318,7 @@ public class VoiceInteractionService extends Service {
        synchronized (mLock) {
            // Allow only one concurrent recognition via the APIs.
            safelyShutdownHotwordDetector();
            mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
            mHotwordDetector = new AlwaysOnHotwordDetector(this, keyphrase, locale, callback,
                    mKeyphraseEnrollmentInfo, mSystemService);
        }
        return mHotwordDetector;
+153 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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 android.app;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;

import android.content.ComponentName;
import android.net.Uri;
import android.os.Parcel;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.google.common.base.Strings;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.lang.reflect.Field;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class AutomaticZenRuleTest {
    private static final String CLASS = "android.app.AutomaticZenRule";

    @Test
    public void testLongFields_inConstructor() {
        String longString = Strings.repeat("A", 65536);
        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));

        // test both variants where there's an owner, and where there's a configuration activity
        AutomaticZenRule rule1 = new AutomaticZenRule(
                longString, // name
                new ComponentName("pkg", longString), // owner
                null,  // configuration activity
                longUri, // conditionId
                null, // zen policy
                0, // interruption filter
                true); // enabled

        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule1.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getOwner().getClassName().length());

        AutomaticZenRule rule2 = new AutomaticZenRule(
                longString, // name
                null, // owner
                new ComponentName(longString, "SomeClassName"), // configuration activity
                longUri, // conditionId
                null, // zen policy
                0, // interruption filter
                false); // enabled

        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule2.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule2.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule2.getConfigurationActivity().getPackageName().length());
    }

    @Test
    public void testLongFields_inSetters() {
        String longString = Strings.repeat("A", 65536);
        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));

        AutomaticZenRule rule = new AutomaticZenRule(
                "sensible name",
                new ComponentName("pkg", "ShortClass"),
                null,
                Uri.parse("uri://short"),
                null, 0, true);

        rule.setName(longString);
        rule.setConditionId(longUri);
        rule.setConfigurationActivity(new ComponentName(longString, longString));

        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule.getConfigurationActivity().getPackageName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                rule.getConfigurationActivity().getClassName().length());
    }

    @Test
    public void testLongInputsFromParcel() {
        // Create a rule with long fields, set directly via reflection so that we can confirm that
        // a rule with too-long fields that comes in via a parcel has its fields truncated directly.
        AutomaticZenRule rule = new AutomaticZenRule(
                "placeholder",
                new ComponentName("place", "holder"),
                null,
                Uri.parse("uri://placeholder"),
                null, 0, true);

        try {
            String longString = Strings.repeat("A", 65536);
            Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
            Field name = Class.forName(CLASS).getDeclaredField("name");
            name.setAccessible(true);
            name.set(rule, longString);
            Field conditionId = Class.forName(CLASS).getDeclaredField("conditionId");
            conditionId.setAccessible(true);
            conditionId.set(rule, longUri);
            Field owner = Class.forName(CLASS).getDeclaredField("owner");
            owner.setAccessible(true);
            owner.set(rule, new ComponentName(longString, longString));
            Field configActivity = Class.forName(CLASS).getDeclaredField("configurationActivity");
            configActivity.setAccessible(true);
            configActivity.set(rule, new ComponentName(longString, longString));
        } catch (NoSuchFieldException e) {
            fail(e.toString());
        } catch (ClassNotFoundException e) {
            fail(e.toString());
        } catch (IllegalAccessException e) {
            fail(e.toString());
        }

        Parcel parcel = Parcel.obtain();
        rule.writeToParcel(parcel, 0);
        parcel.setDataPosition(0);

        AutomaticZenRule fromParcel = new AutomaticZenRule(parcel);
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, fromParcel.getName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getConditionId().toString().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getConfigurationActivity().getPackageName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getConfigurationActivity().getClassName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getOwner().getPackageName().length());
        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
                fromParcel.getOwner().getClassName().length());
    }
}
Loading