diff options
22 files changed, 612 insertions, 201 deletions
diff --git a/api/api.go b/api/api.go index 5e5f60ee993f..9cd0132e2c6c 100644 --- a/api/api.go +++ b/api/api.go @@ -27,6 +27,7 @@ import ( const art = "art.module.public.api" const conscrypt = "conscrypt.module.public.api" const i18n = "i18n.module.public.api" + var core_libraries_modules = []string{art, conscrypt, i18n} // The intention behind this soong plugin is to generate a number of "merged" @@ -92,6 +93,8 @@ type fgProps struct { type MergedTxtDefinition struct { // "current.txt" or "removed.txt" TxtFilename string + // Filename in the new dist dir. "android.txt" or "android-removed.txt" + DistFilename string // The module for the non-updatable / non-module part of the api. BaseTxt string // The list of modules that are relevant for this merged txt. @@ -112,7 +115,6 @@ func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) { if txt.Scope != "public" { filename = txt.Scope + "-" + filename } - props := genruleProps{} props.Name = proptools.StringPtr(ctx.ModuleName() + "-" + filename) props.Tools = []string{"metalava"} @@ -126,9 +128,9 @@ func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) { Dest: proptools.StringPtr(filename), }, { - Targets: []string{"sdk"}, + Targets: []string{"api_txt", "sdk"}, Dir: proptools.StringPtr("apistubs/android/" + txt.Scope + "/api"), - Dest: proptools.StringPtr(txt.TxtFilename), + Dest: proptools.StringPtr(txt.DistFilename), }, } props.Visibility = []string{"//visibility:public"} @@ -242,34 +244,39 @@ func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_ var textFiles []MergedTxtDefinition tagSuffix := []string{".api.txt}", ".removed-api.txt}"} + distFilename := []string{"android.txt", "android-removed.txt"} for i, f := range []string{"current.txt", "removed.txt"} { textFiles = append(textFiles, MergedTxtDefinition{ - TxtFilename: f, - BaseTxt: ":non-updatable-" + f, - Modules: bootclasspath, - ModuleTag: "{.public" + tagSuffix[i], - Scope: "public", + TxtFilename: f, + DistFilename: distFilename[i], + BaseTxt: ":non-updatable-" + f, + Modules: bootclasspath, + ModuleTag: "{.public" + tagSuffix[i], + Scope: "public", }) textFiles = append(textFiles, MergedTxtDefinition{ - TxtFilename: f, - BaseTxt: ":non-updatable-system-" + f, - Modules: bootclasspath, - ModuleTag: "{.system" + tagSuffix[i], - Scope: "system", + TxtFilename: f, + DistFilename: distFilename[i], + BaseTxt: ":non-updatable-system-" + f, + Modules: bootclasspath, + ModuleTag: "{.system" + tagSuffix[i], + Scope: "system", }) textFiles = append(textFiles, MergedTxtDefinition{ - TxtFilename: f, - BaseTxt: ":non-updatable-module-lib-" + f, - Modules: bootclasspath, - ModuleTag: "{.module-lib" + tagSuffix[i], - Scope: "module-lib", + TxtFilename: f, + DistFilename: distFilename[i], + BaseTxt: ":non-updatable-module-lib-" + f, + Modules: bootclasspath, + ModuleTag: "{.module-lib" + tagSuffix[i], + Scope: "module-lib", }) textFiles = append(textFiles, MergedTxtDefinition{ - TxtFilename: f, - BaseTxt: ":non-updatable-system-server-" + f, - Modules: system_server_classpath, - ModuleTag: "{.system-server" + tagSuffix[i], - Scope: "system-server", + TxtFilename: f, + DistFilename: distFilename[i], + BaseTxt: ":non-updatable-system-server-" + f, + Modules: system_server_classpath, + ModuleTag: "{.system-server" + tagSuffix[i], + Scope: "system-server", }) } for _, txt := range textFiles { diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java index 9c044b5e632e..8b9ab4c57574 100644 --- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java +++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java @@ -37,6 +37,8 @@ import com.android.internal.os.BaseCommand; import com.android.internal.telecom.ITelecomService; import java.io.PrintStream; +import java.util.Arrays; +import java.util.stream.Collectors; public final class Telecom extends BaseCommand { @@ -88,6 +90,10 @@ public final class Telecom extends BaseCommand { private static final String COMMAND_GET_MAX_PHONES = "get-max-phones"; private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER = "set-test-emergency-phone-account-package-filter"; + /** + * Command used to emit a distinct "mark" in the logs. + */ + private static final String COMMAND_LOG_MARK = "log-mark"; private ComponentName mComponent; private String mAccountId; @@ -156,6 +162,8 @@ public final class Telecom extends BaseCommand { + " package name that will be used for test emergency calls. To clear," + " send an empty package name. Real emergency calls will still be placed" + " over Telephony.\n" + + "telecom log-mark <MESSAGE>: emits a message into the telecom logs. Useful for " + + "testers to indicate where in the logs various test steps take place.\n" ); } @@ -257,6 +265,9 @@ public final class Telecom extends BaseCommand { case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER: runSetEmergencyPhoneAccountPackageFilter(); break; + case COMMAND_LOG_MARK: + runLogMark(); + break; default: Log.w(this, "onRun: unknown command: %s", command); throw new IllegalArgumentException ("unknown command '" + command + "'"); @@ -429,6 +440,11 @@ public final class Telecom extends BaseCommand { } + private void runLogMark() throws RemoteException { + String message = Arrays.stream(mArgs.peekRemainingArgs()).collect(Collectors.joining(" ")); + mTelecomService.requestLogMark(message); + } + private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException { if (TextUtils.isEmpty(mArgs.peekNextArg())) { return null; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 2c02be7dc6b9..c3be18e2b160 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -622,6 +622,9 @@ public class Notification implements Parcelable * Bit to be bitwise-ored into the {@link #flags} field that should be * set if you would only like the sound, vibrate and ticker to be played * if the notification was not already showing. + * + * Note that using this flag will stop any ongoing alerting behaviour such + * as sound, vibration or blinking notification LED. */ public static final int FLAG_ONLY_ALERT_ONCE = 0x00000008; @@ -4601,6 +4604,9 @@ public class Notification implements Parcelable * Set this flag if you would only like the sound, vibrate * and ticker to be played if the notification is not already showing. * + * Note that using this flag will stop any ongoing alerting behaviour such + * as sound, vibration or blinking notification LED. + * * @see Notification#FLAG_ONLY_ALERT_ONCE */ @NonNull diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java index 69e63133eb03..2d1a3fe8e967 100644 --- a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java +++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java @@ -57,9 +57,11 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork @NonNull private final Set<Integer> mAllowedSpecificCarrierIds; private static final String ROAMING_MATCH_KEY = "mRoamingMatchCriteria"; + private static final int DEFAULT_ROAMING_MATCH_CRITERIA = MATCH_ANY; private final int mRoamingMatchCriteria; private static final String OPPORTUNISTIC_MATCH_KEY = "mOpportunisticMatchCriteria"; + private static final int DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA = MATCH_ANY; private final int mOpportunisticMatchCriteria; private VcnCellUnderlyingNetworkTemplate( @@ -253,23 +255,31 @@ public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetwork /** @hide */ @Override void dumpTransportSpecificFields(IndentingPrintWriter pw) { - pw.println("mAllowedNetworkPlmnIds: " + mAllowedNetworkPlmnIds.toString()); - pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds.toString()); - pw.println("mRoamingMatchCriteria: " + getMatchCriteriaString(mRoamingMatchCriteria)); - pw.println( - "mOpportunisticMatchCriteria: " - + getMatchCriteriaString(mOpportunisticMatchCriteria)); + if (!mAllowedNetworkPlmnIds.isEmpty()) { + pw.println("mAllowedNetworkPlmnIds: " + mAllowedNetworkPlmnIds); + } + if (!mAllowedNetworkPlmnIds.isEmpty()) { + pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds); + } + if (mRoamingMatchCriteria != DEFAULT_ROAMING_MATCH_CRITERIA) { + pw.println("mRoamingMatchCriteria: " + getMatchCriteriaString(mRoamingMatchCriteria)); + } + if (mOpportunisticMatchCriteria != DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA) { + pw.println( + "mOpportunisticMatchCriteria: " + + getMatchCriteriaString(mOpportunisticMatchCriteria)); + } } /** This class is used to incrementally build VcnCellUnderlyingNetworkTemplate objects. */ public static final class Builder { - private int mMeteredMatchCriteria = MATCH_ANY; + private int mMeteredMatchCriteria = DEFAULT_METERED_MATCH_CRITERIA; @NonNull private final Set<String> mAllowedNetworkPlmnIds = new ArraySet<>(); @NonNull private final Set<Integer> mAllowedSpecificCarrierIds = new ArraySet<>(); - private int mRoamingMatchCriteria = MATCH_ANY; - private int mOpportunisticMatchCriteria = MATCH_ANY; + private int mRoamingMatchCriteria = DEFAULT_ROAMING_MATCH_CRITERIA; + private int mOpportunisticMatchCriteria = DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA; private int mMinEntryUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; private int mMinExitUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 390c3b9453c2..f1b110ab29c8 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -172,11 +172,11 @@ public class VcnManager { * * <p>An app that has carrier privileges for any of the subscriptions in the given group may * clear a VCN configuration. This API is ONLY permitted for callers running as the primary - * user. Any active VCN will be torn down. + * user. Any active VCN associated with this configuration will be torn down. * * @param subscriptionGroup the subscription group that the configuration should be applied to - * @throws SecurityException if the caller does not have carrier privileges, or is not running - * as the primary user + * @throws SecurityException if the caller does not have carrier privileges, is not the owner of + * the associated configuration, or is not running as the primary user * @throws IOException if the configuration failed to be cleared from disk. This may occur due * to temporary disk errors, or more permanent conditions such as a full disk. */ @@ -196,8 +196,13 @@ public class VcnManager { /** * Retrieves the list of Subscription Groups for which a VCN Configuration has been set. * - * <p>The returned list will include only subscription groups for which the carrier app is - * privileged, and which have an associated {@link VcnConfig}. + * <p>The returned list will include only subscription groups for which an associated {@link + * VcnConfig} exists, and the app is either: + * + * <ul> + * <li>Carrier privileged for that subscription group, or + * <li>Is the provisioning package of the config + * </ul> * * @throws SecurityException if the caller is not running as the primary user */ diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java index 3a9ca3edded7..9235d0913295 100644 --- a/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java @@ -15,8 +15,6 @@ */ package android.net.vcn; -import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; - import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntDef; @@ -88,6 +86,9 @@ public abstract class VcnUnderlyingNetworkTemplate { /** @hide */ static final String METERED_MATCH_KEY = "mMeteredMatchCriteria"; + /** @hide */ + static final int DEFAULT_METERED_MATCH_CRITERIA = MATCH_ANY; + private final int mMeteredMatchCriteria; /** @hide */ @@ -237,11 +238,21 @@ public abstract class VcnUnderlyingNetworkTemplate { pw.println(this.getClass().getSimpleName() + ":"); pw.increaseIndent(); - pw.println("mMeteredMatchCriteria: " + getMatchCriteriaString(mMeteredMatchCriteria)); - pw.println("mMinEntryUpstreamBandwidthKbps: " + mMinEntryUpstreamBandwidthKbps); - pw.println("mMinExitUpstreamBandwidthKbps: " + mMinExitUpstreamBandwidthKbps); - pw.println("mMinEntryDownstreamBandwidthKbps: " + mMinEntryDownstreamBandwidthKbps); - pw.println("mMinExitDownstreamBandwidthKbps: " + mMinExitDownstreamBandwidthKbps); + if (mMeteredMatchCriteria != DEFAULT_METERED_MATCH_CRITERIA) { + pw.println("mMeteredMatchCriteria: " + getMatchCriteriaString(mMeteredMatchCriteria)); + } + if (mMinEntryUpstreamBandwidthKbps != DEFAULT_MIN_BANDWIDTH_KBPS) { + pw.println("mMinEntryUpstreamBandwidthKbps: " + mMinEntryUpstreamBandwidthKbps); + } + if (mMinExitUpstreamBandwidthKbps != DEFAULT_MIN_BANDWIDTH_KBPS) { + pw.println("mMinExitUpstreamBandwidthKbps: " + mMinExitUpstreamBandwidthKbps); + } + if (mMinEntryDownstreamBandwidthKbps != DEFAULT_MIN_BANDWIDTH_KBPS) { + pw.println("mMinEntryDownstreamBandwidthKbps: " + mMinEntryDownstreamBandwidthKbps); + } + if (mMinExitDownstreamBandwidthKbps != DEFAULT_MIN_BANDWIDTH_KBPS) { + pw.println("mMinExitDownstreamBandwidthKbps: " + mMinExitDownstreamBandwidthKbps); + } dumpTransportSpecificFields(pw); pw.decreaseIndent(); diff --git a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java index 23a07abdf0cb..2544a6d63561 100644 --- a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java +++ b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java @@ -147,7 +147,9 @@ public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetwork /** @hide */ @Override void dumpTransportSpecificFields(IndentingPrintWriter pw) { - pw.println("mSsids: " + mSsids); + if (!mSsids.isEmpty()) { + pw.println("mSsids: " + mSsids); + } } /** diff --git a/core/java/com/android/internal/security/OWNERS b/core/java/com/android/internal/security/OWNERS index 41d1d6687c42..b702df80cc7e 100644 --- a/core/java/com/android/internal/security/OWNERS +++ b/core/java/com/android/internal/security/OWNERS @@ -1,3 +1,3 @@ # Bug component: 36824 -per-file VerityUtils.java = victorhsieh@google.com +per-file VerityUtils.java = file:platform/system/security:/fsverity/OWNERS diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 626a2124a70b..4072687c87cc 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -81,7 +81,7 @@ per-file LayoutlibLoader.cpp = file:/graphics/java/android/graphics/OWNERS per-file LayoutlibLoader.cpp = diegoperez@google.com, jgaillard@google.com # Verity -per-file com_android_internal_security_Verity* = ebiggers@google.com, victorhsieh@google.com +per-file com_android_internal_security_Verity* = file:platform/system/security:/fsverity/OWNERS # VINTF per-file android_os_VintfObject* = file:platform/system/libvintf:/OWNERS diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 4d8d4dbf67fa..71b51ff8fbb6 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -991,7 +991,7 @@ jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz, end = i; i++; } else if ((mode&PROC_QUOTES) != 0) { - while (buffer[i] != '"' && i < endIndex) { + while (i < endIndex && buffer[i] != '"') { i++; } end = i; diff --git a/data/keyboards/Vendor_0e6f_Product_f501.kl b/data/keyboards/Vendor_0e6f_Product_f501.kl new file mode 100644 index 000000000000..b46c005353b1 --- /dev/null +++ b/data/keyboards/Vendor_0e6f_Product_f501.kl @@ -0,0 +1,55 @@ +# 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. + +# +# XBox-compatible USB Controller +# + +key 304 BUTTON_A +key 305 BUTTON_B +key 307 BUTTON_X +key 308 BUTTON_Y +key 310 BUTTON_L1 +key 311 BUTTON_R1 + +key 317 BUTTON_THUMBL +key 318 BUTTON_THUMBR + +# Left and right stick. +# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd. +# This confuses applications that rely on the flat value because the joystick actually +# settles in a flat range of +/- 4096 or so. +axis 0x00 X flat 4096 +axis 0x01 Y flat 4096 +axis 0x03 Z flat 4096 +axis 0x04 RZ flat 4096 + +# Triggers. +axis 0x02 LTRIGGER +axis 0x05 RTRIGGER + +# Hat. +axis 0x10 HAT_X +axis 0x11 HAT_Y + +# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt + +# Button labeled as "BACK" (left-pointing triangle) +key 314 BUTTON_SELECT + +# The branded "X" button in the center of the controller +key 316 BUTTON_MODE + +# Button labeled as "START" (right-pointing triangle) +key 315 BUTTON_START diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 54bab4ad3780..ffd041f60e26 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -1637,8 +1637,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * Sets whether the keystore requires the screen to be unlocked before allowing decryption * using this key. If this is set to {@code true}, any attempt to decrypt or sign using this * key while the screen is locked will fail. A locked device requires a PIN, password, - * biometric, or other trusted factor to access. While the screen is locked, the key can - * still be used for encryption or signature verification. + * biometric, or other trusted factor to access. While the screen is locked, any associated + * public key can still be used (e.g for signature verification). */ @NonNull public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) { diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index 62e53d62fd2a..a41399fb0d0d 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -16,17 +16,18 @@ package com.android.dynsystem; +import android.annotation.NonNull; import android.content.Context; import android.gsi.AvbPublicKey; import android.gsi.IGsiService; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; -import android.os.MemoryFile; -import android.os.ParcelFileDescriptor; +import android.os.SharedMemory; import android.os.SystemProperties; import android.os.image.DynamicSystemManager; import android.service.persistentdata.PersistentDataBlockManager; +import android.system.ErrnoException; import android.util.Log; import android.util.Pair; import android.util.Range; @@ -39,6 +40,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Enumeration; import java.util.List; @@ -154,6 +156,22 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { void onResult(int resultCode, Throwable detail); } + private static class MappedMemoryBuffer implements AutoCloseable { + public ByteBuffer mBuffer; + + MappedMemoryBuffer(@NonNull ByteBuffer buffer) { + mBuffer = buffer; + } + + @Override + public void close() { + if (mBuffer != null) { + SharedMemory.unmap(mBuffer); + mBuffer = null; + } + } + } + private final int mSharedMemorySize; private final String mUrl; private final String mDsuSlot; @@ -674,59 +692,66 @@ class InstallationAsyncTask extends AsyncTask<String, Long, Throwable> { Log.d(TAG, "Start installing: " + partitionName); - MemoryFile memoryFile = new MemoryFile("dsu_" + partitionName, mSharedMemorySize); - ParcelFileDescriptor pfd = new ParcelFileDescriptor(memoryFile.getFileDescriptor()); - - mInstallationSession.setAshmem(pfd, memoryFile.length()); - - initPartitionProgress(partitionName, partitionSize, /* readonly = */ true); - publishProgress(/* installedSize = */ 0L); - long prevInstalledSize = 0; - long installedSize = 0; - byte[] bytes = new byte[memoryFile.length()]; - ExecutorService executor = Executors.newSingleThreadExecutor(); - Future<Boolean> submitPromise = null; - - while (true) { - final int numBytesRead = sis.read(bytes, 0, bytes.length); - - if (submitPromise != null) { - // Wait until the previous submit task is complete. - while (true) { - try { - if (!submitPromise.get()) { - throw new IOException("Failed submitFromAshmem() to DynamicSystem"); + try (SharedMemory sharedMemory = + SharedMemory.create("dsu_buffer_" + partitionName, mSharedMemorySize); + MappedMemoryBuffer mappedBuffer = + new MappedMemoryBuffer(sharedMemory.mapReadWrite())) { + mInstallationSession.setAshmem(sharedMemory.getFdDup(), sharedMemory.getSize()); + + initPartitionProgress(partitionName, partitionSize, /* readonly = */ true); + publishProgress(/* installedSize = */ 0L); + + long installedSize = 0; + byte[] readBuffer = new byte[sharedMemory.getSize()]; + ByteBuffer buffer = mappedBuffer.mBuffer; + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future<Boolean> submitPromise = null; + + while (true) { + final int numBytesRead = sis.read(readBuffer, 0, readBuffer.length); + + if (submitPromise != null) { + // Wait until the previous submit task is complete. + while (true) { + try { + if (!submitPromise.get()) { + throw new IOException("Failed submitFromAshmem() to DynamicSystem"); + } + break; + } catch (InterruptedException e) { + // Ignore. } - break; - } catch (InterruptedException e) { - // Ignore. } - } - // Publish the progress of the previous submit task. - if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) { - publishProgress(installedSize); - prevInstalledSize = installedSize; + // Publish the progress of the previous submit task. + if (installedSize > prevInstalledSize + MIN_PROGRESS_TO_PUBLISH) { + publishProgress(installedSize); + prevInstalledSize = installedSize; + } } - } - // Ensure the previous submit task (submitPromise) is complete before exiting the loop. - if (numBytesRead < 0) { - break; - } + // Ensure the previous submit task (submitPromise) is complete before exiting the + // loop. + if (numBytesRead < 0) { + break; + } - if (isCancelled()) { - return; - } + if (isCancelled()) { + return; + } - memoryFile.writeBytes(bytes, 0, 0, numBytesRead); - submitPromise = - executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead)); + buffer.position(0); + buffer.put(readBuffer, 0, numBytesRead); + submitPromise = + executor.submit(() -> mInstallationSession.submitFromAshmem(numBytesRead)); - // Even though we update the bytes counter here, the actual progress is updated only - // after the submit task (submitPromise) is complete. - installedSize += numBytesRead; + // Even though we update the bytes counter here, the actual progress is updated only + // after the submit task (submitPromise) is complete. + installedSize += numBytesRead; + } + } catch (ErrnoException e) { + e.rethrowAsIOException(); } AvbPublicKey avbPublicKey = new AvbPublicKey(); diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 2d328d8b0949..eefeee3918b3 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -87,6 +87,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -153,7 +154,7 @@ import java.util.concurrent.TimeUnit; public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private static final String TAG = VcnManagementService.class.getSimpleName(); private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); - private static final int LOCAL_LOG_LINE_COUNT = 128; + private static final int LOCAL_LOG_LINE_COUNT = 512; // Public for use in all other VCN classes @NonNull public static final LocalLog LOCAL_LOG = new LocalLog(LOCAL_LOG_LINE_COUNT); @@ -172,7 +173,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final VcnNetworkProvider mNetworkProvider; @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb; @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; - @NonNull private final BroadcastReceiver mPkgChangeReceiver; + @NonNull private final BroadcastReceiver mVcnBroadcastReceiver; @NonNull private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback(); @@ -217,28 +218,17 @@ public class VcnManagementService extends IVcnManagementService.Stub { mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); - mPkgChangeReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - - if (Intent.ACTION_PACKAGE_ADDED.equals(action) - || Intent.ACTION_PACKAGE_REPLACED.equals(action) - || Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - mTelephonySubscriptionTracker.handleSubscriptionsChanged(); - } else { - Log.wtf(TAG, "received unexpected intent: " + action); - } - } - }; + mVcnBroadcastReceiver = new VcnBroadcastReceiver(); final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); + intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); intentFilter.addDataScheme("package"); mContext.registerReceiver( - mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler); + mVcnBroadcastReceiver, intentFilter, null /* broadcastPermission */, mHandler); // Run on handler to ensure I/O does not block system server startup mHandler.post(() -> { @@ -443,6 +433,53 @@ public class VcnManagementService extends IVcnManagementService.Stub { return Objects.equals(subGrp, snapshot.getActiveDataSubscriptionGroup()); } + private class VcnBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + switch (action) { + case Intent.ACTION_PACKAGE_ADDED: // Fallthrough + case Intent.ACTION_PACKAGE_REPLACED: // Fallthrough + case Intent.ACTION_PACKAGE_REMOVED: + // Reevaluate subscriptions + mTelephonySubscriptionTracker.handleSubscriptionsChanged(); + + break; + case Intent.ACTION_PACKAGE_FULLY_REMOVED: + case Intent.ACTION_PACKAGE_DATA_CLEARED: + final String pkgName = intent.getData().getSchemeSpecificPart(); + + if (pkgName == null || pkgName.isEmpty()) { + logWtf("Package name was empty or null for intent with action" + action); + return; + } + + // Clear configs for the packages that had data cleared, or removed. + synchronized (mLock) { + final List<ParcelUuid> toRemove = new ArrayList<>(); + for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) { + if (pkgName.equals(entry.getValue().getProvisioningPackageName())) { + toRemove.add(entry.getKey()); + } + } + + for (ParcelUuid subGrp : toRemove) { + stopAndClearVcnConfigInternalLocked(subGrp); + } + + if (!toRemove.isEmpty()) { + writeConfigsToDiskLocked(); + } + } + + break; + default: + Slog.wtf(TAG, "received unexpected intent: " + action); + } + } + } + private class VcnSubscriptionTrackerCallback implements TelephonySubscriptionTrackerCallback { /** * Handles subscription group changes, as notified by {@link TelephonySubscriptionTracker} @@ -456,7 +493,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { synchronized (mLock) { final TelephonySubscriptionSnapshot oldSnapshot = mLastSnapshot; mLastSnapshot = snapshot; - logDbg("new snapshot: " + mLastSnapshot); + logInfo("new snapshot: " + mLastSnapshot); // Start any VCN instances as necessary for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) { @@ -504,6 +541,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final Map<ParcelUuid, Set<Integer>> currSubGrpMappings = getSubGroupToSubIdMappings(mLastSnapshot); if (!currSubGrpMappings.equals(oldSubGrpMappings)) { + garbageCollectAndWriteVcnConfigsLocked(); notifyAllPolicyListenersLocked(); } } @@ -522,6 +560,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void stopVcnLocked(@NonNull ParcelUuid uuidToTeardown) { + logInfo("Stopping VCN config for subGrp: " + uuidToTeardown); + // Remove in 2 steps. Make sure teardownAsync is triggered before removing from the map. final Vcn vcnToTeardown = mVcns.get(uuidToTeardown); if (vcnToTeardown == null) { @@ -567,7 +607,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @GuardedBy("mLock") private void startVcnLocked(@NonNull ParcelUuid subscriptionGroup, @NonNull VcnConfig config) { - logDbg("Starting VCN config for subGrp: " + subscriptionGroup); + logInfo("Starting VCN config for subGrp: " + subscriptionGroup); // TODO(b/193687515): Support multiple VCNs active at the same time if (!mVcns.isEmpty()) { @@ -626,7 +666,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { if (!config.getProvisioningPackageName().equals(opPkgName)) { throw new IllegalArgumentException("Mismatched caller and VcnConfig creator"); } - logDbg("VCN config updated for subGrp: " + subscriptionGroup); + logInfo("VCN config updated for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); @@ -643,6 +683,39 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } + private void enforceCarrierPrivilegeOrProvisioningPackage( + @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) { + // Only apps running in the primary (system) user are allowed to configure the VCN. This is + // in line with Telephony's behavior with regards to binding to a Carrier App provided + // CarrierConfigService. + enforcePrimaryUser(); + + if (isProvisioningPackageForConfig(subscriptionGroup, pkg)) { + return; + } + + // Must NOT be called from cleared binder identity, since this checks user calling identity + enforceCallingUserAndCarrierPrivilege(subscriptionGroup, pkg); + } + + private boolean isProvisioningPackageForConfig( + @NonNull ParcelUuid subscriptionGroup, @NonNull String pkg) { + // Try-finally to return early if matching owned subscription found. + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + final VcnConfig config = mConfigs.get(subscriptionGroup); + if (config != null && pkg.equals(config.getProvisioningPackageName())) { + return true; + } + } + } finally { + Binder.restoreCallingIdentity(identity); + } + + return false; + } + /** * Clears the VcnManagementService for a given subscription group. * @@ -652,35 +725,60 @@ public class VcnManagementService extends IVcnManagementService.Stub { public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); requireNonNull(opPkgName, "opPkgName was null"); - logDbg("VCN config cleared for subGrp: " + subscriptionGroup); + logInfo("VCN config cleared for subGrp: " + subscriptionGroup); mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), opPkgName); - enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); + enforceCarrierPrivilegeOrProvisioningPackage(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { - mConfigs.remove(subscriptionGroup); - final boolean vcnExists = mVcns.containsKey(subscriptionGroup); + stopAndClearVcnConfigInternalLocked(subscriptionGroup); + writeConfigsToDiskLocked(); + } + }); + } - stopVcnLocked(subscriptionGroup); + private void stopAndClearVcnConfigInternalLocked(@NonNull ParcelUuid subscriptionGroup) { + mConfigs.remove(subscriptionGroup); + final boolean vcnExists = mVcns.containsKey(subscriptionGroup); - if (vcnExists) { - // TODO(b/181789060): invoke asynchronously after Vcn notifies through - // VcnCallback - notifyAllPermissionedStatusCallbacksLocked( - subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); - } + stopVcnLocked(subscriptionGroup); - writeConfigsToDiskLocked(); + if (vcnExists) { + // TODO(b/181789060): invoke asynchronously after Vcn notifies through + // VcnCallback + notifyAllPermissionedStatusCallbacksLocked( + subscriptionGroup, VCN_STATUS_CODE_NOT_CONFIGURED); + } + } + + private void garbageCollectAndWriteVcnConfigsLocked() { + final SubscriptionManager subMgr = mContext.getSystemService(SubscriptionManager.class); + + boolean shouldWrite = false; + + final Iterator<ParcelUuid> configsIterator = mConfigs.keySet().iterator(); + while (configsIterator.hasNext()) { + final ParcelUuid subGrp = configsIterator.next(); + + final List<SubscriptionInfo> subscriptions = subMgr.getSubscriptionsInGroup(subGrp); + if (subscriptions == null || subscriptions.isEmpty()) { + // Trim subGrps with no more subscriptions; must have moved to another subGrp + configsIterator.remove(); + shouldWrite = true; } - }); + } + + if (shouldWrite) { + writeConfigsToDiskLocked(); + } } /** * Retrieves the list of subscription groups with configured VcnConfigs * - * <p>Limited to subscription groups for which the caller is carrier privileged. + * <p>Limited to subscription groups for which the caller had configured. * * <p>Implements the IVcnManagementService Binder interface. */ @@ -696,7 +794,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { final List<ParcelUuid> result = new ArrayList<>(); synchronized (mLock) { for (ParcelUuid subGrp : mConfigs.keySet()) { - if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName)) { + if (mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subGrp, opPkgName) + || isProvisioningPackageForConfig(subGrp, opPkgName)) { result.add(subGrp); } } @@ -1050,24 +1149,34 @@ public class VcnManagementService extends IVcnManagementService.Stub { Slog.d(TAG, msg, tr); } + private void logInfo(String msg) { + Slog.i(TAG, msg); + LOCAL_LOG.log("[INFO] [" + TAG + "] " + msg); + } + + private void logInfo(String msg, Throwable tr) { + Slog.i(TAG, msg, tr); + LOCAL_LOG.log("[INFO] [" + TAG + "] " + msg + tr); + } + private void logErr(String msg) { Slog.e(TAG, msg); - LOCAL_LOG.log(TAG + " ERR: " + msg); + LOCAL_LOG.log("[ERR] [" + TAG + "] " + msg); } private void logErr(String msg, Throwable tr) { Slog.e(TAG, msg, tr); - LOCAL_LOG.log(TAG + " ERR: " + msg + tr); + LOCAL_LOG.log("[ERR ] [" + TAG + "] " + msg + tr); } private void logWtf(String msg) { Slog.wtf(TAG, msg); - LOCAL_LOG.log(TAG + " WTF: " + msg); + LOCAL_LOG.log("[WTF] [" + TAG + "] " + msg); } private void logWtf(String msg, Throwable tr) { Slog.wtf(TAG, msg, tr); - LOCAL_LOG.log(TAG + " WTF: " + msg + tr); + LOCAL_LOG.log("[WTF ] [" + TAG + "] " + msg + tr); } /** diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 4c9b28b1bd18..d9e4828e7eb4 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.BIND_VPN_SERVICE; import static android.Manifest.permission.CONTROL_VPN; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN; @@ -2549,6 +2550,7 @@ public class Vpn { req = new NetworkRequest.Builder() .clearCapabilities() .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .addCapability(NET_CAPABILITY_NOT_VPN) .build(); } else { // Basically, the request here is referring to the default request which is defined diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java index 1c296e5b5640..8647680e52a6 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java @@ -83,7 +83,9 @@ public final class HdmiCecStandbyModeHandler { private final HdmiCecLocalDevice mDevice; private final SparseArray<CecMessageHandler> mCecMessageHandlers = new SparseArray<>(); - private final CecMessageHandler mDefaultHandler = new Aborter( + private final CecMessageHandler mDefaultHandler; + + private final CecMessageHandler mAborterUnrecognizedOpcode = new Aborter( Constants.ABORT_UNRECOGNIZED_OPCODE); private final CecMessageHandler mAborterIncorrectMode = new Aborter( Constants.ABORT_NOT_IN_CORRECT_MODE); @@ -95,6 +97,10 @@ public final class HdmiCecStandbyModeHandler { mUserControlProcessedHandler = new UserControlProcessedHandler(); private void addCommonHandlers() { + addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler); + } + + private void addTvHandlers() { addHandler(Constants.MESSAGE_ACTIVE_SOURCE, mBystander); addHandler(Constants.MESSAGE_REQUEST_ACTIVE_SOURCE, mBystander); addHandler(Constants.MESSAGE_ROUTING_CHANGE, mBystander); @@ -118,17 +124,13 @@ public final class HdmiCecStandbyModeHandler { addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser); addHandler(Constants.MESSAGE_GIVE_FEATURES, mBypasser); - addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler); - addHandler(Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS, mBypasser); addHandler(Constants.MESSAGE_ABORT, mBypasser); addHandler(Constants.MESSAGE_GET_CEC_VERSION, mBypasser); addHandler(Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, mAborterIncorrectMode); addHandler(Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE, mAborterIncorrectMode); - } - private void addTvHandlers() { addHandler(Constants.MESSAGE_IMAGE_VIEW_ON, mAutoOnHandler); addHandler(Constants.MESSAGE_TEXT_VIEW_ON, mAutoOnHandler); @@ -153,6 +155,9 @@ public final class HdmiCecStandbyModeHandler { addCommonHandlers(); if (mDevice.getType() == HdmiDeviceInfo.DEVICE_TV) { addTvHandlers(); + mDefaultHandler = mAborterUnrecognizedOpcode; + } else { + mDefaultHandler = mBypasser; } } diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index f29c40f74353..37f04501bf28 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -341,6 +341,9 @@ public class Vcn extends Handler { if (gatewayConnection == null) { logWtf("Found gatewayConnectionConfig without GatewayConnection"); } else { + logInfo( + "Config updated, restarting gateway " + + gatewayConnection.getLogPrefix()); gatewayConnection.teardownAsynchronously(); } } @@ -397,7 +400,7 @@ public class Vcn extends Handler { // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - logDbg("Request already satisfied by existing VcnGatewayConnection: " + request); + logVdbg("Request already satisfied by existing VcnGatewayConnection: " + request); return; } } @@ -407,8 +410,6 @@ public class Vcn extends Handler { for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { - logDbg("Bringing up new VcnGatewayConnection for request " + request); - if (getExposedCapabilitiesForMobileDataState(gatewayConnectionConfig).isEmpty()) { // Skip; this network does not provide any services if mobile data is disabled. continue; @@ -424,6 +425,7 @@ public class Vcn extends Handler { return; } + logInfo("Bringing up new VcnGatewayConnection for request " + request); final VcnGatewayConnection vcnGatewayConnection = mDeps.newVcnGatewayConnection( mVcnContext, @@ -455,7 +457,7 @@ public class Vcn extends Handler { } private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { - logDbg("VcnGatewayConnection quit: " + config); + logInfo("VcnGatewayConnection quit: " + config); mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied @@ -534,7 +536,7 @@ public class Vcn extends Handler { // Trigger re-evaluation of all requests; mobile data state impacts supported caps. mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); - logDbg("Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled")); + logInfo("Mobile data " + (mIsMobileDataEnabled ? "enabled" : "disabled")); } } @@ -569,11 +571,11 @@ public class Vcn extends Handler { } private String getLogPrefix() { - return "[" + return "(" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "-" + System.identityHashCode(this) - + "] "; + + ") "; } private void logVdbg(String msg) { diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index be38005abb63..cefd8efe9658 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -732,14 +732,11 @@ public class VcnGatewayConnection extends StateMachine { logDbg("Triggering async teardown"); sendDisconnectRequestedAndAcquireWakelock( DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */); - - // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this - // is also called asynchronously when a NetworkAgent becomes unwanted } @Override protected void onQuitting() { - logDbg("Quitting VcnGatewayConnection"); + logInfo("Quitting VcnGatewayConnection"); if (mNetworkAgent != null) { logWtf("NetworkAgent was non-null in onQuitting"); @@ -794,7 +791,7 @@ public class VcnGatewayConnection extends StateMachine { // TODO(b/180132994): explore safely removing this Thread check mVcnContext.ensureRunningOnLooperThread(); - logDbg( + logInfo( "Selected underlying network changed: " + (underlying == null ? null : underlying.network)); @@ -1335,7 +1332,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) { // TODO(b/180526152): notify VcnStatusCallback for Network loss - logDbg("Tearing down. Cause: " + info.reason); + logInfo("Tearing down. Cause: " + info.reason + "; quitting = " + info.shouldQuit); if (info.shouldQuit) { mIsQuitting.setTrue(); } @@ -1353,7 +1350,7 @@ public class VcnGatewayConnection extends StateMachine { protected void handleSafeModeTimeoutExceeded() { mSafeModeTimeoutAlarm = null; - logDbg("Entering safe mode after timeout exceeded"); + logInfo("Entering safe mode after timeout exceeded"); // Connectivity for this GatewayConnection is broken; tear down the Network. teardownNetwork(); @@ -1362,7 +1359,7 @@ public class VcnGatewayConnection extends StateMachine { } protected void logUnexpectedEvent(int what) { - logDbg( + logVdbg( "Unexpected event code " + what + " in state " @@ -1672,7 +1669,7 @@ public class VcnGatewayConnection extends StateMachine { return; } - logDbg("NetworkAgent was unwanted"); + logInfo("NetworkAgent was unwanted"); teardownAsynchronously(); } /* networkUnwantedCallback */, (status) -> { @@ -1748,7 +1745,7 @@ public class VcnGatewayConnection extends StateMachine { tunnelIface, IpSecManager.DIRECTION_FWD, transform); } } catch (IOException e) { - logDbg("Transform application failed for network " + token, e); + logInfo("Transform application failed for network " + token, e); sessionLost(token, e); } } @@ -1782,7 +1779,7 @@ public class VcnGatewayConnection extends StateMachine { tunnelIface.removeAddress(address.getAddress(), address.getPrefixLength()); } } catch (IOException e) { - logDbg("Adding address to tunnel failed for token " + token, e); + logInfo("Adding address to tunnel failed for token " + token, e); sessionLost(token, e); } } @@ -1862,7 +1859,7 @@ public class VcnGatewayConnection extends StateMachine { } private void handleMigrationCompleted(EventMigrationCompletedInfo migrationCompletedInfo) { - logDbg("Migration completed: " + mUnderlying.network); + logInfo("Migration completed: " + mUnderlying.network); applyTransform( mCurrentToken, @@ -1890,7 +1887,7 @@ public class VcnGatewayConnection extends StateMachine { mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; if (mUnderlying == null) { - logDbg("Underlying network lost"); + logInfo("Underlying network lost"); // Ignored for now; a new network may be coming up. If none does, the delayed // NETWORK_LOST disconnect will be fired, and tear down the session + network. @@ -1900,7 +1897,7 @@ public class VcnGatewayConnection extends StateMachine { // mUnderlying assumed non-null, given check above. // If network changed, migrate. Otherwise, update any existing networkAgent. if (oldUnderlying == null || !oldUnderlying.network.equals(mUnderlying.network)) { - logDbg("Migrating to new network: " + mUnderlying.network); + logInfo("Migrating to new network: " + mUnderlying.network); mIkeSession.setNetwork(mUnderlying.network); } else { // oldUnderlying is non-null & underlying network itself has not changed @@ -2168,13 +2165,13 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onClosedExceptionally(@NonNull IkeException exception) { - logDbg("IkeClosedExceptionally for token " + mToken, exception); + logInfo("IkeClosedExceptionally for token " + mToken, exception); sessionClosed(mToken, exception); } @Override public void onError(@NonNull IkeProtocolException exception) { - logDbg("IkeError for token " + mToken, exception); + logInfo("IkeError for token " + mToken, exception); // Non-fatal, log and continue. } } @@ -2208,7 +2205,7 @@ public class VcnGatewayConnection extends StateMachine { @Override public void onClosedExceptionally(@NonNull IkeException exception) { - logDbg("ChildClosedExceptionally for token " + mToken, exception); + logInfo("ChildClosedExceptionally for token " + mToken, exception); sessionLost(mToken, exception); } @@ -2234,14 +2231,19 @@ public class VcnGatewayConnection extends StateMachine { } } - private String getLogPrefix() { - return "[" + // Used in Vcn.java, but must be public for mockito to mock this. + public String getLogPrefix() { + return "(" + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + "-" + mConnectionConfig.getGatewayConnectionName() + "-" + System.identityHashCode(this) - + "] "; + + ") "; + } + + private String getTagLogPrefix() { + return "[ " + TAG + " " + getLogPrefix() + "]"; } private void logVdbg(String msg) { @@ -2258,34 +2260,44 @@ public class VcnGatewayConnection extends StateMachine { Slog.d(TAG, getLogPrefix() + msg, tr); } + private void logInfo(String msg) { + Slog.i(TAG, getLogPrefix() + msg); + LOCAL_LOG.log("[INFO] " + getTagLogPrefix() + msg); + } + + private void logInfo(String msg, Throwable tr) { + Slog.i(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log("[INFO] " + getTagLogPrefix() + msg + tr); + } + private void logWarn(String msg) { Slog.w(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg); + LOCAL_LOG.log("[WARN] " + getTagLogPrefix() + msg); } private void logWarn(String msg, Throwable tr) { Slog.w(TAG, getLogPrefix() + msg, tr); - LOCAL_LOG.log(getLogPrefix() + "WARN: " + msg + tr); + LOCAL_LOG.log("[WARN] " + getTagLogPrefix() + msg + tr); } private void logErr(String msg) { Slog.e(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg); + LOCAL_LOG.log("[ERR ] " + getTagLogPrefix() + msg); } private void logErr(String msg, Throwable tr) { Slog.e(TAG, getLogPrefix() + msg, tr); - LOCAL_LOG.log(getLogPrefix() + "ERR: " + msg + tr); + LOCAL_LOG.log("[ERR ] " + getTagLogPrefix() + msg + tr); } private void logWtf(String msg) { Slog.wtf(TAG, getLogPrefix() + msg); - LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg); + LOCAL_LOG.log("[WTF ] " + msg); } private void logWtf(String msg, Throwable tr) { Slog.wtf(TAG, getLogPrefix() + msg, tr); - LOCAL_LOG.log(getLogPrefix() + "WTF: " + msg + tr); + LOCAL_LOG.log("[WTF ] " + msg + tr); } /** diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index ca2e449ffc25..a3babf7c9fff 100644 --- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -48,6 +48,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import com.android.server.vcn.VcnContext; +import com.android.server.vcn.util.LogUtils; import java.util.ArrayList; import java.util.Collections; @@ -368,6 +369,18 @@ public class UnderlyingNetworkController { return; } + String allNetworkPriorities = ""; + for (UnderlyingNetworkRecord record : sorted) { + if (!allNetworkPriorities.isEmpty()) { + allNetworkPriorities += ", "; + } + allNetworkPriorities += record.network + ": " + record.getPriorityClass(); + } + logInfo( + "Selected network changed to " + + (candidate == null ? null : candidate.network) + + ", selected from list: " + + allNetworkPriorities); mCurrentRecord = candidate; mCb.onSelectedUnderlyingNetworkChanged(mCurrentRecord); } @@ -478,14 +491,38 @@ public class UnderlyingNetworkController { } } - private static void logWtf(String msg) { + private String getLogPrefix() { + return "(" + + LogUtils.getHashedSubscriptionGroup(mSubscriptionGroup) + + "-" + + mConnectionConfig.getGatewayConnectionName() + + "-" + + System.identityHashCode(this) + + ") "; + } + + private String getTagLogPrefix() { + return "[ " + TAG + " " + getLogPrefix() + "]"; + } + + private void logInfo(String msg) { + Slog.i(TAG, getLogPrefix() + msg); + LOCAL_LOG.log("[INFO] " + getTagLogPrefix() + msg); + } + + private void logInfo(String msg, Throwable tr) { + Slog.i(TAG, getLogPrefix() + msg, tr); + LOCAL_LOG.log("[INFO] " + getTagLogPrefix() + msg + tr); + } + + private void logWtf(String msg) { Slog.wtf(TAG, msg); - LOCAL_LOG.log(TAG + " WTF: " + msg); + LOCAL_LOG.log(TAG + "[WTF ] " + getTagLogPrefix() + msg); } - private static void logWtf(String msg, Throwable tr) { + private void logWtf(String msg, Throwable tr) { Slog.wtf(TAG, msg, tr); - LOCAL_LOG.log(TAG + " WTF: " + msg + tr); + LOCAL_LOG.log(TAG + "[WTF ] " + getTagLogPrefix() + msg + tr); } /** Dumps the state of this record for logging and debugging purposes. */ diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java index c0488b18cb65..06f92805ad2b 100644 --- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java +++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkRecord.java @@ -41,11 +41,15 @@ import java.util.Objects; * @hide */ public class UnderlyingNetworkRecord { + private static final int PRIORITY_CLASS_INVALID = Integer.MAX_VALUE; + @NonNull public final Network network; @NonNull public final NetworkCapabilities networkCapabilities; @NonNull public final LinkProperties linkProperties; public final boolean isBlocked; + private int mPriorityClass = PRIORITY_CLASS_INVALID; + @VisibleForTesting(visibility = Visibility.PRIVATE) public UnderlyingNetworkRecord( @NonNull Network network, @@ -58,6 +62,34 @@ public class UnderlyingNetworkRecord { this.isBlocked = isBlocked; } + private int getOrCalculatePriorityClass( + VcnContext vcnContext, + List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, + ParcelUuid subscriptionGroup, + TelephonySubscriptionSnapshot snapshot, + UnderlyingNetworkRecord currentlySelected, + PersistableBundle carrierConfig) { + // Never changes after the underlying network record is created. + if (mPriorityClass == PRIORITY_CLASS_INVALID) { + mPriorityClass = + NetworkPriorityClassifier.calculatePriorityClass( + vcnContext, + this, + underlyingNetworkTemplates, + subscriptionGroup, + snapshot, + currentlySelected, + carrierConfig); + } + + return mPriorityClass; + } + + // Used in UnderlyingNetworkController + int getPriorityClass() { + return mPriorityClass; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -84,18 +116,16 @@ public class UnderlyingNetworkRecord { PersistableBundle carrierConfig) { return (left, right) -> { final int leftIndex = - NetworkPriorityClassifier.calculatePriorityClass( + left.getOrCalculatePriorityClass( vcnContext, - left, underlyingNetworkTemplates, subscriptionGroup, snapshot, currentlySelected, carrierConfig); final int rightIndex = - NetworkPriorityClassifier.calculatePriorityClass( + right.getOrCalculatePriorityClass( vcnContext, - right, underlyingNetworkTemplates, subscriptionGroup, snapshot, @@ -142,16 +172,15 @@ public class UnderlyingNetworkRecord { pw.increaseIndent(); final int priorityIndex = - NetworkPriorityClassifier.calculatePriorityClass( + getOrCalculatePriorityClass( vcnContext, - this, underlyingNetworkTemplates, subscriptionGroup, snapshot, currentlySelected, carrierConfig); - pw.println("Priority index:" + priorityIndex); + pw.println("Priority index: " + priorityIndex); pw.println("mNetwork: " + network); pw.println("mNetworkCapabilities: " + networkCapabilities); pw.println("mLinkProperties: " + linkProperties); diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 6f286d9f3006..23b578748370 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -344,6 +344,11 @@ interface ITelecomService { void setTestDefaultCallRedirectionApp(String packageName); + /** + * @see TelecomServiceImpl#requestLogMark + */ + void requestLogMark(in String message); + void setTestPhoneAcctSuggestionComponent(String flattenedComponentName); void setTestDefaultCallScreeningApp(String packageName); diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index bb98bc0bab53..54b3c400af4f 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -65,6 +65,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; +import android.net.Uri; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; @@ -114,18 +115,24 @@ import java.util.UUID; public class VcnManagementServiceTest { private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); + private static final String TEST_PACKAGE_NAME_2 = "TEST_PKG_2"; private static final String TEST_CB_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName() + ".callback"; private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1)); + private static final ParcelUuid TEST_UUID_3 = new ParcelUuid(new UUID(2, 2)); private static final VcnConfig TEST_VCN_CONFIG; + private static final VcnConfig TEST_VCN_CONFIG_PKG_2; private static final int TEST_UID = Process.FIRST_APPLICATION_UID; static { final Context mockConfigContext = mock(Context.class); - doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName(); + doReturn(TEST_PACKAGE_NAME).when(mockConfigContext).getOpPackageName(); TEST_VCN_CONFIG = VcnConfigTest.buildTestConfig(mockConfigContext); + + doReturn(TEST_PACKAGE_NAME_2).when(mockConfigContext).getOpPackageName(); + TEST_VCN_CONFIG_PKG_2 = VcnConfigTest.buildTestConfig(mockConfigContext); } private static final Map<ParcelUuid, VcnConfig> TEST_VCN_CONFIG_MAP = @@ -246,18 +253,24 @@ public class VcnManagementServiceTest { eq(android.Manifest.permission.NETWORK_FACTORY), any()); } + private void setupMockedCarrierPrivilege(boolean isPrivileged) { + setupMockedCarrierPrivilege(isPrivileged, TEST_PACKAGE_NAME); + } + + private void setupMockedCarrierPrivilege(boolean isPrivileged, String pkg) { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) .getSubscriptionsInGroup(any()); doReturn(mTelMgr) .when(mTelMgr) .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); - doReturn(isPrivileged - ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS - : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) + doReturn( + isPrivileged + ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS + : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) .when(mTelMgr) - .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME)); + .checkCarrierPrivilegesForPackage(eq(pkg)); } @Test @@ -414,7 +427,13 @@ public class VcnManagementServiceTest { private BroadcastReceiver getPackageChangeReceiver() { final ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class); - verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any()); + verify(mMockContext).registerReceiver(captor.capture(), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_ADDED) + && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) + && filter.hasAction(Intent.ACTION_PACKAGE_DATA_CLEARED) + && filter.hasAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); + }), any(), any()); return captor.getValue(); } @@ -539,6 +558,44 @@ public class VcnManagementServiceTest { } @Test + public void testPackageChangeListener_packageDataCleared() throws Exception { + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); + final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1); + + final BroadcastReceiver receiver = getPackageChangeReceiver(); + assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs()); + + final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED); + intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID)); + + receiver.onReceive(mMockContext, intent); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + + @Test + public void testPackageChangeListener_packageFullyRemoved() throws Exception { + triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); + final Vcn vcn = mVcnMgmtSvc.getAllVcns().get(TEST_UUID_1); + + final BroadcastReceiver receiver = getPackageChangeReceiver(); + assertEquals(TEST_VCN_CONFIG_MAP, mVcnMgmtSvc.getConfigs()); + + final Intent intent = new Intent(Intent.ACTION_PACKAGE_FULLY_REMOVED); + intent.setData(Uri.parse("package:" + TEST_PACKAGE_NAME)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(TEST_UID)); + + receiver.onReceive(mMockContext, intent); + mTestLooper.dispatchAll(); + verify(vcn).teardownAsynchronously(); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + + @Test public void testSetVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -578,7 +635,7 @@ public class VcnManagementServiceTest { @Test public void testSetVcnConfigMismatchedPackages() throws Exception { try { - mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, "IncorrectPackage"); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_1, TEST_VCN_CONFIG, TEST_PACKAGE_NAME_2); fail("Expected exception due to mismatched packages in config and method call"); } catch (IllegalArgumentException expected) { verify(mMockPolicyListener, never()).onPolicyChanged(); @@ -678,11 +735,12 @@ public class VcnManagementServiceTest { } @Test - public void testClearVcnConfigRequiresCarrierPrivileges() throws Exception { + public void testClearVcnConfigRequiresCarrierPrivilegesOrProvisioningPackage() + throws Exception { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } @@ -691,20 +749,32 @@ public class VcnManagementServiceTest { @Test public void testClearVcnConfigMismatchedPackages() throws Exception { try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage"); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); fail("Expected security exception due to mismatched packages"); } catch (SecurityException expected) { } } @Test - public void testClearVcnConfig() throws Exception { + public void testClearVcnConfig_callerIsProvisioningPackage() throws Exception { + // Lose carrier privileges to test that provisioning package is sufficient. + setupMockedCarrierPrivilege(false); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } @Test + public void testClearVcnConfig_callerIsCarrierPrivileged() throws Exception { + setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2); + + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME_2); + assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); + verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); + } + + @Test public void testClearVcnConfigNotifiesStatusCallback() throws Exception { setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */); mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); @@ -755,11 +825,12 @@ public class VcnManagementServiceTest { @Test public void testGetConfiguredSubscriptionGroupsMismatchedPackages() throws Exception { - final String badPackage = "IncorrectPackage"; - doThrow(new SecurityException()).when(mAppOpsMgr).checkPackage(TEST_UID, badPackage); + doThrow(new SecurityException()) + .when(mAppOpsMgr) + .checkPackage(TEST_UID, TEST_PACKAGE_NAME_2); try { - mVcnMgmtSvc.getConfiguredSubscriptionGroups(badPackage); + mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME_2); fail("Expected security exception due to mismatched packages"); } catch (SecurityException expected) { } @@ -767,14 +838,16 @@ public class VcnManagementServiceTest { @Test public void testGetConfiguredSubscriptionGroups() throws Exception { + setupMockedCarrierPrivilege(true, TEST_PACKAGE_NAME_2); mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); + mVcnMgmtSvc.setVcnConfig(TEST_UUID_3, TEST_VCN_CONFIG_PKG_2, TEST_PACKAGE_NAME_2); - // Assert that if both UUID 1 and 2 are provisioned, the caller only gets ones that they are - // privileged for. + // Assert that if UUIDs 1, 2 and 3 are provisioned, the caller only gets ones that they are + // privileged for, or are the provisioning package of. triggerSubscriptionTrackerCbAndGetSnapshot(TEST_UUID_1, Collections.singleton(TEST_UUID_1)); final List<ParcelUuid> subGrps = mVcnMgmtSvc.getConfiguredSubscriptionGroups(TEST_PACKAGE_NAME); - assertEquals(Collections.singletonList(TEST_UUID_1), subGrps); + assertEquals(Arrays.asList(new ParcelUuid[] {TEST_UUID_1, TEST_UUID_2}), subGrps); } @Test |