Merge "MediaCodec: don't cache buffers until requested"
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 39f055b..a542c5c 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -134,11 +134,7 @@
     defaults: ["android-non-updatable-doc-stubs-defaults"],
     srcs: [":all-modules-public-stubs-source"],
     args: metalava_framework_docs_args,
-    api_levels_annotations_enabled: true,
-    api_levels_annotations_dirs: [
-        "sdk-dir",
-        "api-versions-jars-dir",
-    ],
+    api_levels_module: "api_versions_public",
     aidl: {
         include_dirs: [
             "packages/modules/Connectivity/framework/aidl-export",
diff --git a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
index 517e3ce..31c92ba 100644
--- a/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/ZipFilePerfTest.java
@@ -70,6 +70,9 @@
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
             ZipFile zf = new ZipFile(mFile);
+            state.pauseTiming();
+            zf.close();
+            state.resumeTiming();
         }
     }
 
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
index 32117dc..03c9d43 100644
--- a/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
+++ b/apct-tests/perftests/core/src/android/libcore/regression/ExpensiveObjectsPerfTest.java
@@ -141,15 +141,6 @@
     }
 
     @Test
-    public void timeNumberFormatTrivialFormatLong() {
-        NumberFormat nf = NumberFormat.getInstance(Locale.US);
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            nf.format(1024L);
-        }
-    }
-
-    @Test
     public void timeLongToString() {
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         while (state.keepRunning()) {
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java
deleted file mode 100644
index f2b7fdf..0000000
--- a/apct-tests/perftests/core/src/android/libcore/regression/HostnameVerifierPerfTest.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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.libcore.regression;
-
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
-import android.test.suitebuilder.annotation.LargeTest;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.io.ByteArrayInputStream;
-import java.net.URL;
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.util.Arrays;
-import java.util.Collection;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-
-/**
- * This benchmark makes a real HTTP connection to a handful of hosts and
- * captures the served certificates as a byte array. It then verifies each
- * certificate in the benchmark loop, being careful to convert from the
- * byte[] to the certificate each time. Otherwise the certificate class
- * caches previous results which skews the results of the benchmark: In practice
- * each certificate instance is verified once and then released.
- */
-@RunWith(Parameterized.class)
-@LargeTest
-public final class HostnameVerifierPerfTest {
-    @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
-
-    @Parameters(name = "mHost({0})")
-    public static Collection<Object[]> data() {
-        return Arrays.asList(
-                new Object[][] {
-                        {"m.google.com"},
-                        {"www.google.com"},
-                        {"www.amazon.com"},
-                        {"www.ubs.com"}
-                });
-    }
-
-    @Parameterized.Parameter(0)
-    public String mHost;
-
-
-    private String mHostname;
-    private HostnameVerifier mHostnameVerifier;
-    private byte[][] mEncodedCertificates;
-
-    @Before
-    public void setUp() throws Exception {
-        URL url = new URL("https", mHost, "/");
-        mHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
-        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
-        connection.setHostnameVerifier(new HostnameVerifier() {
-            public boolean verify(String mHostname, SSLSession sslSession) {
-                try {
-                    mEncodedCertificates = certificatesToBytes(sslSession.getPeerCertificates());
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-                HostnameVerifierPerfTest.this.mHostname = mHostname;
-                return true;
-            }
-        });
-        connection.getInputStream();
-        connection.disconnect();
-    }
-
-    @Test
-    public void timeVerify() throws Exception {
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            final Certificate[] certificates = bytesToCertificates(mEncodedCertificates);
-            FakeSSLSession sslSession = new FakeSSLSession() {
-                @Override public Certificate[] getPeerCertificates() {
-                    return certificates;
-                }
-            };
-            mHostnameVerifier.verify(mHostname, sslSession);
-        }
-    }
-
-    private byte[][] certificatesToBytes(Certificate[] certificates) throws Exception {
-        byte[][] result = new byte[certificates.length][];
-        for (int i = 0, certificatesLength = certificates.length; i < certificatesLength; i++) {
-            result[i] = certificates[i].getEncoded();
-        }
-        return result;
-    }
-
-    private Certificate[] bytesToCertificates(byte[][] encodedCertificates) throws Exception {
-        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
-        Certificate[] result = new Certificate[encodedCertificates.length];
-        for (int i = 0; i < encodedCertificates.length; i++) {
-            result[i] = certificateFactory.generateCertificate(
-                    new ByteArrayInputStream(encodedCertificates[i]));
-        }
-        return result;
-    }
-
-    private static class FakeSSLSession implements SSLSession {
-        public int getApplicationBufferSize() {
-            throw new UnsupportedOperationException();
-        }
-        public String getCipherSuite() {
-            throw new UnsupportedOperationException();
-        }
-        public long getCreationTime() {
-            throw new UnsupportedOperationException();
-        }
-        public byte[] getId() {
-            throw new UnsupportedOperationException();
-        }
-        public long getLastAccessedTime() {
-            throw new UnsupportedOperationException();
-        }
-        public Certificate[] getLocalCertificates() {
-            throw new UnsupportedOperationException();
-        }
-        public Principal getLocalPrincipal() {
-            throw new UnsupportedOperationException();
-        }
-        public int getPacketBufferSize() {
-            throw new UnsupportedOperationException();
-        }
-        public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
-            throw new UnsupportedOperationException();
-        }
-        public Certificate[] getPeerCertificates() {
-            throw new UnsupportedOperationException();
-        }
-        public String getPeerHost() {
-            throw new UnsupportedOperationException();
-        }
-        public int getPeerPort() {
-            throw new UnsupportedOperationException();
-        }
-        public Principal getPeerPrincipal() {
-            throw new UnsupportedOperationException();
-        }
-        public String getProtocol() {
-            throw new UnsupportedOperationException();
-        }
-        public SSLSessionContext getSessionContext() {
-            throw new UnsupportedOperationException();
-        }
-        public Object getValue(String name) {
-            throw new UnsupportedOperationException();
-        }
-        public String[] getValueNames() {
-            throw new UnsupportedOperationException();
-        }
-        public void invalidate() {
-            throw new UnsupportedOperationException();
-        }
-        public boolean isValid() {
-            throw new UnsupportedOperationException();
-        }
-        public void putValue(String name, Object value) {
-            throw new UnsupportedOperationException();
-        }
-        public void removeValue(String name) {
-            throw new UnsupportedOperationException();
-        }
-    }
-}
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
new file mode 100644
index 0000000..5ff2b22
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/libcore/regression/NumberFormatTrivialFormatLongPerfTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.libcore.regression;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * Benchmarks creation and cloning various expensive objects.
+ */
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class NumberFormatTrivialFormatLongPerfTest {
+    @Rule
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+    @Test
+    public void timeNumberFormatTrivialFormatLong() {
+        NumberFormat nf = NumberFormat.getInstance(Locale.US);
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {
+            nf.format(1024L);
+        }
+    }
+}
diff --git a/api/api.go b/api/api.go
index 9cd0132..93f1354 100644
--- a/api/api.go
+++ b/api/api.go
@@ -179,7 +179,7 @@
 	// Note: order matters: first parameter is the full api-versions.xml
 	// after that the stubs files in any order
 	// stubs files are all modules that export API surfaces EXCEPT ART
-	props.Srcs = append([]string{":framework-doc-stubs{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...)
+	props.Srcs = append([]string{":api_versions_public{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...)
 	props.Dists = []android.Dist{{Targets: []string{"sdk"}}}
 	ctx.CreateModule(genrule.GenRuleFactory, &props)
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 52fd7be..6582623 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -509,7 +509,8 @@
     resolution = limitSurfaceSize(resolution.width, resolution.height);
     // create the native surface
     sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
-            resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
+            resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565,
+            ISurfaceComposerClient::eOpaque);
 
     SurfaceComposerClient::Transaction t;
 
diff --git a/core/api/current.txt b/core/api/current.txt
index e4fc9f3..18286eb 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -11473,7 +11473,7 @@
     field public static final String FEATURE_CAMERA_LEVEL_FULL = "android.hardware.camera.level.full";
     field public static final String FEATURE_CANT_SAVE_STATE = "android.software.cant_save_state";
     field public static final String FEATURE_COMPANION_DEVICE_SETUP = "android.software.companion_device_setup";
-    field public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
+    field @Deprecated public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final String FEATURE_CONTROLS = "android.software.controls";
     field public static final String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
@@ -11544,12 +11544,18 @@
     field public static final String FEATURE_SIP = "android.software.sip";
     field public static final String FEATURE_SIP_VOIP = "android.software.sip.voip";
     field public static final String FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
+    field public static final String FEATURE_TELECOM = "android.software.telecom";
     field public static final String FEATURE_TELEPHONY = "android.hardware.telephony";
+    field public static final String FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling";
     field public static final String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
+    field public static final String FEATURE_TELEPHONY_DATA = "android.hardware.telephony.data";
     field public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
     field public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
     field public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
     field public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
+    field public static final String FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging";
+    field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio";
+    field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
     field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
     field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
@@ -21438,6 +21444,7 @@
     field public static final String KEY_VIDEO_QP_P_MAX = "video-qp-p-max";
     field public static final String KEY_VIDEO_QP_P_MIN = "video-qp-p-min";
     field public static final String KEY_WIDTH = "width";
+    field public static final String LOG_SESSION_ID = "log-session-id";
     field public static final String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
     field public static final String MIMETYPE_AUDIO_AC4 = "audio/ac4";
@@ -41215,8 +41222,11 @@
     field public static final String MMS_CONFIG_UA_PROF_URL = "uaProfUrl";
     field public static final String MMS_CONFIG_USER_AGENT = "userAgent";
     field public static final int MMS_ERROR_CONFIGURATION_ERROR = 7; // 0x7
+    field public static final int MMS_ERROR_DATA_DISABLED = 11; // 0xb
     field public static final int MMS_ERROR_HTTP_FAILURE = 4; // 0x4
+    field public static final int MMS_ERROR_INACTIVE_SUBSCRIPTION = 10; // 0xa
     field public static final int MMS_ERROR_INVALID_APN = 2; // 0x2
+    field public static final int MMS_ERROR_INVALID_SUBSCRIPTION_ID = 9; // 0x9
     field public static final int MMS_ERROR_IO_ERROR = 5; // 0x5
     field public static final int MMS_ERROR_NO_DATA_NETWORK = 8; // 0x8
     field public static final int MMS_ERROR_RETRY = 6; // 0x6
diff --git a/core/java/android/app/time/ExternalTimeSuggestion.java b/core/java/android/app/time/ExternalTimeSuggestion.java
index a7c0e5c..a7828ab 100644
--- a/core/java/android/app/time/ExternalTimeSuggestion.java
+++ b/core/java/android/app/time/ExternalTimeSuggestion.java
@@ -19,15 +19,14 @@
 import android.annotation.CurrentTimeMillisLong;
 import android.annotation.ElapsedRealtimeLong;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.app.timedetector.TimeSuggestionHelper;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
 import java.util.List;
 import java.util.Objects;
 
@@ -75,7 +74,9 @@
     public static final @NonNull Creator<ExternalTimeSuggestion> CREATOR =
             new Creator<ExternalTimeSuggestion>() {
                 public ExternalTimeSuggestion createFromParcel(Parcel in) {
-                    return ExternalTimeSuggestion.createFromParcel(in);
+                    TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+                            ExternalTimeSuggestion.class, in);
+                    return new ExternalTimeSuggestion(helper);
                 }
 
                 public ExternalTimeSuggestion[] newArray(int size) {
@@ -83,10 +84,7 @@
                 }
             };
 
-    @NonNull
-    private final TimestampedValue<Long> mUnixEpochTime;
-    @Nullable
-    private ArrayList<String> mDebugInfo;
+    @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
 
     /**
      * Creates a time suggestion cross-referenced to the elapsed realtime clock. See {@link
@@ -98,17 +96,12 @@
      */
     public ExternalTimeSuggestion(@ElapsedRealtimeLong long elapsedRealtimeMillis,
             @CurrentTimeMillisLong long suggestionMillis) {
-        mUnixEpochTime = new TimestampedValue(elapsedRealtimeMillis, suggestionMillis);
+        mTimeSuggestionHelper = new TimeSuggestionHelper(ExternalTimeSuggestion.class,
+                new TimestampedValue<>(elapsedRealtimeMillis, suggestionMillis));
     }
 
-    private static ExternalTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
-        ExternalTimeSuggestion suggestion =
-                new ExternalTimeSuggestion(utcTime.getReferenceTimeMillis(), utcTime.getValue());
-        @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
-        suggestion.mDebugInfo = debugInfo;
-        return suggestion;
+    private ExternalTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+        mTimeSuggestionHelper = Objects.requireNonNull(helper);
     }
 
     @Override
@@ -118,8 +111,7 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeParcelable(mUnixEpochTime, 0);
-        dest.writeList(mDebugInfo);
+        mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
     }
 
     /**
@@ -127,7 +119,7 @@
      */
     @NonNull
     public TimestampedValue<Long> getUnixEpochTime() {
-        return mUnixEpochTime;
+        return mTimeSuggestionHelper.getUnixEpochTime();
     }
 
     /**
@@ -135,9 +127,7 @@
      */
     @NonNull
     public List<String> getDebugInfo() {
-        return mDebugInfo == null
-                ? Collections.emptyList()
-                : Collections.unmodifiableList(mDebugInfo);
+        return mTimeSuggestionHelper.getDebugInfo();
     }
 
     /**
@@ -146,10 +136,7 @@
      * #equals(Object)} and {@link #hashCode()}.
      */
     public void addDebugInfo(@NonNull String... debugInfos) {
-        if (mDebugInfo == null) {
-            mDebugInfo = new ArrayList<>();
-        }
-        mDebugInfo.addAll(Arrays.asList(debugInfos));
+        mTimeSuggestionHelper.addDebugInfo(debugInfos);
     }
 
     @Override
@@ -161,18 +148,29 @@
             return false;
         }
         ExternalTimeSuggestion that = (ExternalTimeSuggestion) o;
-        return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+        return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mUnixEpochTime);
+        return mTimeSuggestionHelper.hashCode();
     }
 
     @Override
     public String toString() {
-        return "ExternalTimeSuggestion{" + "mUnixEpochTime=" + mUnixEpochTime
-                + ", mDebugInfo=" + mDebugInfo
-                + '}';
+        return mTimeSuggestionHelper.handleToString();
+    }
+
+    /** @hide */
+    public static ExternalTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+            throws IllegalArgumentException {
+        return new ExternalTimeSuggestion(
+                TimeSuggestionHelper.handleParseCommandLineArg(ExternalTimeSuggestion.class, cmd));
+    }
+
+    /** @hide */
+    public static void printCommandLineOpts(PrintWriter pw) {
+        TimeSuggestionHelper.handlePrintCommandLineOpts(
+                pw, "External", ExternalTimeSuggestion.class);
     }
 }
diff --git a/core/java/android/app/timedetector/GnssTimeSuggestion.java b/core/java/android/app/timedetector/GnssTimeSuggestion.java
index 34f4565..3531b19 100644
--- a/core/java/android/app/timedetector/GnssTimeSuggestion.java
+++ b/core/java/android/app/timedetector/GnssTimeSuggestion.java
@@ -17,30 +17,19 @@
 package android.app.timedetector;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
 import java.util.List;
 import java.util.Objects;
 
 /**
  * A time signal from a GNSS source.
  *
- * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of
- * milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code
- * unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code
- * unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate
- * but it is volatile, so time suggestions cannot be persisted across device resets.
- *
- * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
- * record why the suggestion exists and how it was entered. This information exists only to aid in
- * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
- * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ * <p>See {@link TimeSuggestionHelper} for property information.
  *
  * @hide
  */
@@ -49,7 +38,9 @@
     public static final @NonNull Creator<GnssTimeSuggestion> CREATOR =
             new Creator<GnssTimeSuggestion>() {
                 public GnssTimeSuggestion createFromParcel(Parcel in) {
-                    return GnssTimeSuggestion.createFromParcel(in);
+                    TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+                            GnssTimeSuggestion.class, in);
+                    return new GnssTimeSuggestion(helper);
                 }
 
                 public GnssTimeSuggestion[] newArray(int size) {
@@ -57,21 +48,14 @@
                 }
             };
 
-    @NonNull private final TimestampedValue<Long> mUnixEpochTime;
-    @Nullable private ArrayList<String> mDebugInfo;
+    @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
 
     public GnssTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) {
-        mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
-        Objects.requireNonNull(unixEpochTime.getValue());
+        mTimeSuggestionHelper = new TimeSuggestionHelper(GnssTimeSuggestion.class, unixEpochTime);
     }
 
-    private static GnssTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */);
-        GnssTimeSuggestion suggestion = new GnssTimeSuggestion(unixEpochTime);
-        @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
-        suggestion.mDebugInfo = debugInfo;
-        return suggestion;
+    private GnssTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+        mTimeSuggestionHelper = Objects.requireNonNull(helper);
     }
 
     @Override
@@ -81,19 +65,17 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeParcelable(mUnixEpochTime, 0);
-        dest.writeList(mDebugInfo);
+        mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
     }
 
     @NonNull
     public TimestampedValue<Long> getUnixEpochTime() {
-        return mUnixEpochTime;
+        return mTimeSuggestionHelper.getUnixEpochTime();
     }
 
     @NonNull
     public List<String> getDebugInfo() {
-        return mDebugInfo == null
-                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+        return mTimeSuggestionHelper.getDebugInfo();
     }
 
     /**
@@ -102,10 +84,7 @@
      * {@link #equals(Object)} and {@link #hashCode()}.
      */
     public void addDebugInfo(String... debugInfos) {
-        if (mDebugInfo == null) {
-            mDebugInfo = new ArrayList<>();
-        }
-        mDebugInfo.addAll(Arrays.asList(debugInfos));
+        mTimeSuggestionHelper.addDebugInfo(debugInfos);
     }
 
     @Override
@@ -117,19 +96,29 @@
             return false;
         }
         GnssTimeSuggestion that = (GnssTimeSuggestion) o;
-        return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+        return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mUnixEpochTime);
+        return mTimeSuggestionHelper.hashCode();
     }
 
     @Override
     public String toString() {
-        return "GnssTimeSuggestion{"
-                + "mUnixEpochTime=" + mUnixEpochTime
-                + ", mDebugInfo=" + mDebugInfo
-                + '}';
+        return mTimeSuggestionHelper.handleToString();
+    }
+
+    /** Parses command line args to create a {@link GnssTimeSuggestion}. */
+    public static GnssTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+            throws IllegalArgumentException {
+        TimeSuggestionHelper suggestionHelper =
+                TimeSuggestionHelper.handleParseCommandLineArg(GnssTimeSuggestion.class, cmd);
+        return new GnssTimeSuggestion(suggestionHelper);
+    }
+
+    /** Prints the command line args needed to create a {@link GnssTimeSuggestion}. */
+    public static void printCommandLineOpts(PrintWriter pw) {
+        TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "GNSS", GnssTimeSuggestion.class);
     }
 }
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 76db33b..b447799 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -20,27 +20,17 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
 import java.util.List;
 import java.util.Objects;
 
 /**
  * A time signal from a manual (user provided) source.
  *
- * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of
- * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code unixEpochTime.referenceTimeMillis}
- * is the value of the elapsed realtime clock when the {@code unixEpochTime.value} was established.
- * Note that the elapsed realtime clock is considered accurate but it is volatile, so time
- * suggestions cannot be persisted across device resets.
- *
- * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
- * record why the suggestion exists and how it was entered. This information exists only to aid in
- * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
- * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ * <p>See {@link TimeSuggestionHelper} for property information.
  *
  * @hide
  */
@@ -49,7 +39,9 @@
     public static final @NonNull Creator<ManualTimeSuggestion> CREATOR =
             new Creator<ManualTimeSuggestion>() {
                 public ManualTimeSuggestion createFromParcel(Parcel in) {
-                    return ManualTimeSuggestion.createFromParcel(in);
+                    TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+                            ManualTimeSuggestion.class, in);
+                    return new ManualTimeSuggestion(helper);
                 }
 
                 public ManualTimeSuggestion[] newArray(int size) {
@@ -57,21 +49,14 @@
                 }
             };
 
-    @NonNull private final TimestampedValue<Long> mUnixEpochTime;
-    @Nullable private ArrayList<String> mDebugInfo;
+    @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
 
     public ManualTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) {
-        mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
-        Objects.requireNonNull(unixEpochTime.getValue());
+        mTimeSuggestionHelper = new TimeSuggestionHelper(ManualTimeSuggestion.class, unixEpochTime);
     }
 
-    private static ManualTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */);
-        ManualTimeSuggestion suggestion = new ManualTimeSuggestion(unixEpochTime);
-        @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
-        suggestion.mDebugInfo = debugInfo;
-        return suggestion;
+    private ManualTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+        mTimeSuggestionHelper = Objects.requireNonNull(helper);
     }
 
     @Override
@@ -81,19 +66,17 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeParcelable(mUnixEpochTime, 0);
-        dest.writeList(mDebugInfo);
+        mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
     }
 
     @NonNull
     public TimestampedValue<Long> getUnixEpochTime() {
-        return mUnixEpochTime;
+        return mTimeSuggestionHelper.getUnixEpochTime();
     }
 
     @NonNull
     public List<String> getDebugInfo() {
-        return mDebugInfo == null
-                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+        return mTimeSuggestionHelper.getDebugInfo();
     }
 
     /**
@@ -102,10 +85,7 @@
      * {@link #equals(Object)} and {@link #hashCode()}.
      */
     public void addDebugInfo(String... debugInfos) {
-        if (mDebugInfo == null) {
-            mDebugInfo = new ArrayList<>();
-        }
-        mDebugInfo.addAll(Arrays.asList(debugInfos));
+        mTimeSuggestionHelper.addDebugInfo(debugInfos);
     }
 
     @Override
@@ -117,19 +97,28 @@
             return false;
         }
         ManualTimeSuggestion that = (ManualTimeSuggestion) o;
-        return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+        return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mUnixEpochTime);
+        return mTimeSuggestionHelper.hashCode();
     }
 
     @Override
     public String toString() {
-        return "ManualTimeSuggestion{"
-                + "mUnixEpochTime=" + mUnixEpochTime
-                + ", mDebugInfo=" + mDebugInfo
-                + '}';
+        return mTimeSuggestionHelper.handleToString();
+    }
+
+    /** @hide */
+    public static ManualTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+            throws IllegalArgumentException {
+        return new ManualTimeSuggestion(
+                TimeSuggestionHelper.handleParseCommandLineArg(ManualTimeSuggestion.class, cmd));
+    }
+
+    /** @hide */
+    public static void printCommandLineOpts(PrintWriter pw) {
+        TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "Manual", ManualTimeSuggestion.class);
     }
 }
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
index e22f1d6e..e93c75c 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -17,31 +17,19 @@
 package android.app.timedetector;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.io.PrintWriter;
 import java.util.List;
 import java.util.Objects;
 
 /**
  * A time signal from a network time source like NTP.
  *
- * <p>{@code unixEpochTime} contains the suggested time. The {@code unixEpochTime.value} is the
- * number of milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system.
- * The {@code unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when
- * the {@code unixEpochTime.value} was established. Note that the elapsed realtime clock is
- * considered accurate but it is volatile, so time suggestions cannot be persisted across device
- * resets.
- *
- * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
- * record why the suggestion exists and how it was determined. This information exists only to aid
- * in debugging and therefore is used by {@link #toString()}, but it is not for use in detection
- * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ * <p>See {@link TimeSuggestionHelper} for property information.
  *
  * @hide
  */
@@ -50,7 +38,9 @@
     public static final @NonNull Creator<NetworkTimeSuggestion> CREATOR =
             new Creator<NetworkTimeSuggestion>() {
                 public NetworkTimeSuggestion createFromParcel(Parcel in) {
-                    return NetworkTimeSuggestion.createFromParcel(in);
+                    TimeSuggestionHelper helper = TimeSuggestionHelper.handleCreateFromParcel(
+                            NetworkTimeSuggestion.class, in);
+                    return new NetworkTimeSuggestion(helper);
                 }
 
                 public NetworkTimeSuggestion[] newArray(int size) {
@@ -58,21 +48,15 @@
                 }
             };
 
-    @NonNull private final TimestampedValue<Long> mUnixEpochTime;
-    @Nullable private ArrayList<String> mDebugInfo;
+    @NonNull private final TimeSuggestionHelper mTimeSuggestionHelper;
 
     public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> unixEpochTime) {
-        mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
-        Objects.requireNonNull(unixEpochTime.getValue());
+        mTimeSuggestionHelper = new TimeSuggestionHelper(
+                NetworkTimeSuggestion.class, unixEpochTime);
     }
 
-    private static NetworkTimeSuggestion createFromParcel(Parcel in) {
-        TimestampedValue<Long> unixEpochTime = in.readParcelable(null /* classLoader */);
-        NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(unixEpochTime);
-        @SuppressWarnings("unchecked")
-        ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
-        suggestion.mDebugInfo = debugInfo;
-        return suggestion;
+    private NetworkTimeSuggestion(@NonNull TimeSuggestionHelper helper) {
+        mTimeSuggestionHelper = Objects.requireNonNull(helper);
     }
 
     @Override
@@ -82,35 +66,30 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeParcelable(mUnixEpochTime, 0);
-        dest.writeList(mDebugInfo);
+        mTimeSuggestionHelper.handleWriteToParcel(dest, flags);
     }
 
     @NonNull
     public TimestampedValue<Long> getUnixEpochTime() {
-        return mUnixEpochTime;
+        return mTimeSuggestionHelper.getUnixEpochTime();
     }
 
     @NonNull
     public List<String> getDebugInfo() {
-        return mDebugInfo == null
-                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+        return mTimeSuggestionHelper.getDebugInfo();
     }
 
     /**
      * Associates information with the instance that can be useful for debugging / logging. The
-     * information is present in {@link #toString()} but is not considered for
-     * {@link #equals(Object)} and {@link #hashCode()}.
+     * information is present in {@link #toString()} but is not considered for {@link
+     * #equals(Object)} and {@link #hashCode()}.
      */
     public void addDebugInfo(String... debugInfos) {
-        if (mDebugInfo == null) {
-            mDebugInfo = new ArrayList<>();
-        }
-        mDebugInfo.addAll(Arrays.asList(debugInfos));
+        mTimeSuggestionHelper.addDebugInfo(debugInfos);
     }
 
     @Override
-    public boolean equals(@Nullable Object o) {
+    public boolean equals(Object o) {
         if (this == o) {
             return true;
         }
@@ -118,19 +97,28 @@
             return false;
         }
         NetworkTimeSuggestion that = (NetworkTimeSuggestion) o;
-        return Objects.equals(mUnixEpochTime, that.mUnixEpochTime);
+        return mTimeSuggestionHelper.handleEquals(that.mTimeSuggestionHelper);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mUnixEpochTime);
+        return mTimeSuggestionHelper.hashCode();
     }
 
     @Override
     public String toString() {
-        return "NetworkTimeSuggestion{"
-                + "mUnixEpochTime=" + mUnixEpochTime
-                + ", mDebugInfo=" + mDebugInfo
-                + '}';
+        return mTimeSuggestionHelper.handleToString();
+    }
+
+    /** @hide */
+    public static NetworkTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+            throws IllegalArgumentException {
+        return new NetworkTimeSuggestion(
+                TimeSuggestionHelper.handleParseCommandLineArg(NetworkTimeSuggestion.class, cmd));
+    }
+
+    /** @hide */
+    public static void printCommandLineOpts(PrintWriter pw) {
+        TimeSuggestionHelper.handlePrintCommandLineOpts(pw, "Network", NetworkTimeSuggestion.class);
     }
 }
diff --git a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
index 4ff7517..6f204d6 100644
--- a/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
+++ b/core/java/android/app/timedetector/TelephonyTimeSuggestion.java
@@ -20,8 +20,10 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -88,6 +90,61 @@
         return suggestion;
     }
 
+    /** @hide */
+    public static TelephonyTimeSuggestion parseCommandLineArg(@NonNull ShellCommand cmd)
+            throws IllegalArgumentException {
+        Integer slotIndex = null;
+        Long referenceTimeMillis = null;
+        Long unixEpochTimeMillis = null;
+        String opt;
+        while ((opt = cmd.getNextArg()) != null) {
+            switch (opt) {
+                case "--slot_index": {
+                    slotIndex = Integer.parseInt(cmd.getNextArgRequired());
+                    break;
+                }
+                case "--reference_time": {
+                    referenceTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+                    break;
+                }
+                case "--unix_epoch_time": {
+                    unixEpochTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+                    break;
+                }
+                default: {
+                    throw new IllegalArgumentException("Unknown option: " + opt);
+                }
+            }
+        }
+
+        if (slotIndex == null) {
+            throw new IllegalArgumentException("No slotIndex specified.");
+        }
+        if (referenceTimeMillis == null) {
+            throw new IllegalArgumentException("No referenceTimeMillis specified.");
+        }
+        if (unixEpochTimeMillis == null) {
+            throw new IllegalArgumentException("No unixEpochTimeMillis specified.");
+        }
+
+        TimestampedValue<Long> timeSignal =
+                new TimestampedValue<>(referenceTimeMillis, unixEpochTimeMillis);
+        Builder builder = new Builder(slotIndex)
+                .setUnixEpochTime(timeSignal)
+                .addDebugInfo("Command line injection");
+        return builder.build();
+    }
+
+    /** @hide */
+    public static void printCommandLineOpts(PrintWriter pw) {
+        pw.println("Telephony suggestion options:");
+        pw.println("  --slot_index <number>");
+        pw.println("  --reference_time <elapsed realtime millis>");
+        pw.println("  --unix_epoch_time <Unix epoch time millis>");
+        pw.println();
+        pw.println("See " + TelephonyTimeSuggestion.class.getName() + " for more information");
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index a356230..f0d77761 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -44,6 +44,36 @@
     String SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED = "is_auto_detection_enabled";
 
     /**
+     * A shell command that injects a manual time suggestion.
+     * @hide
+     */
+    String SHELL_COMMAND_SUGGEST_MANUAL_TIME = "suggest_manual_time";
+
+    /**
+     * A shell command that injects a telephony time suggestion.
+     * @hide
+     */
+    String SHELL_COMMAND_SUGGEST_TELEPHONY_TIME = "suggest_telephony_time";
+
+    /**
+     * A shell command that injects a network time suggestion.
+     * @hide
+     */
+    String SHELL_COMMAND_SUGGEST_NETWORK_TIME = "suggest_network_time";
+
+    /**
+     * A shell command that injects a GNSS time suggestion.
+     * @hide
+     */
+    String SHELL_COMMAND_SUGGEST_GNSS_TIME = "suggest_gnss_time";
+
+    /**
+     * A shell command that injects a external time suggestion.
+     * @hide
+     */
+    String SHELL_COMMAND_SUGGEST_EXTERNAL_TIME = "suggest_external_time";
+
+    /**
      * A shared utility method to create a {@link ManualTimeSuggestion}.
      *
      * @hide
diff --git a/core/java/android/app/timedetector/TimeSuggestionHelper.java b/core/java/android/app/timedetector/TimeSuggestionHelper.java
new file mode 100644
index 0000000..9b99be6
--- /dev/null
+++ b/core/java/android/app/timedetector/TimeSuggestionHelper.java
@@ -0,0 +1,209 @@
+/*
+ * 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.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.ShellCommand;
+import android.os.TimestampedValue;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A delegate class to support time suggestion classes that could diverge in the future. This class
+ * exists purely for code re-use and provides support methods. It avoids class inheritance
+ * deliberately to allow each suggestion to evolve in different directions later without affecting
+ * SDK APIs.
+ *
+ * <p>{@code unixEpochTime} is the suggested time. The {@code unixEpochTime.value} is the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC according to the Unix time system. The {@code
+ * unixEpochTime.referenceTimeMillis} is the value of the elapsed realtime clock when the {@code
+ * unixEpochTime.value} was established. Note that the elapsed realtime clock is considered accurate
+ * but it is volatile, so time suggestions cannot be persisted across device resets.
+ *
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists and how it was entered. This information exists only to aid in
+ * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
+ * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ *
+ * @hide
+ */
+public final class TimeSuggestionHelper {
+
+    @NonNull private final Class<?> mHelpedClass;
+    @NonNull private final TimestampedValue<Long> mUnixEpochTime;
+    @Nullable private ArrayList<String> mDebugInfo;
+
+    /** Creates a helper for the specified class, containing the supplied properties. */
+    public TimeSuggestionHelper(@NonNull Class<?> helpedClass,
+            @NonNull TimestampedValue<Long> unixEpochTime) {
+        mHelpedClass = Objects.requireNonNull(helpedClass);
+        mUnixEpochTime = Objects.requireNonNull(unixEpochTime);
+        Objects.requireNonNull(unixEpochTime.getValue());
+    }
+
+    /** See {@link TimeSuggestionHelper} for property details. */
+    @NonNull
+    public TimestampedValue<Long> getUnixEpochTime() {
+        return mUnixEpochTime;
+    }
+
+    /** See {@link TimeSuggestionHelper} for information about {@code debugInfo}. */
+    @NonNull
+    public List<String> getDebugInfo() {
+        return mDebugInfo == null
+                ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging.
+     *
+     * <p>See {@link TimeSuggestionHelper} for more information about {@code debugInfo}.
+     */
+    public void addDebugInfo(@NonNull String debugInfo) {
+        if (mDebugInfo == null) {
+            mDebugInfo = new ArrayList<>();
+        }
+        mDebugInfo.add(debugInfo);
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging. The
+     * information is present in {@link #toString()} but is not considered for
+     * {@link #equals(Object)} and {@link #hashCode()}.
+     */
+    public void addDebugInfo(String... debugInfos) {
+        addDebugInfo(Arrays.asList(debugInfos));
+    }
+
+    /**
+     * Associates information with the instance that can be useful for debugging / logging.
+     *
+     * <p>See {@link TimeSuggestionHelper} for more information about {@code debugInfo}.
+     */
+    public void addDebugInfo(@NonNull List<String> debugInfo) {
+        if (mDebugInfo == null) {
+            mDebugInfo = new ArrayList<>(debugInfo.size());
+        }
+        mDebugInfo.addAll(debugInfo);
+    }
+
+    /**
+     * Implemented in case users call this insteam of {@link #handleEquals(TimeSuggestionHelper)}.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        TimeSuggestionHelper that = (TimeSuggestionHelper) o;
+        return handleEquals(that);
+    }
+
+    /** Used to implement {@link Object#equals(Object)}. */
+    public boolean handleEquals(TimeSuggestionHelper o) {
+        return Objects.equals(mHelpedClass, o.mHelpedClass)
+                && Objects.equals(mUnixEpochTime, o.mUnixEpochTime);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUnixEpochTime);
+    }
+
+    /** Used to implement {@link Object#toString()}. */
+    public String handleToString() {
+        return mHelpedClass.getSimpleName() + "{"
+                + "mUnixEpochTime=" + mUnixEpochTime
+                + ", mDebugInfo=" + mDebugInfo
+                + '}';
+    }
+
+    /** Constructs a helper with suggestion state from a Parcel. */
+    public static TimeSuggestionHelper handleCreateFromParcel(@NonNull Class<?> helpedClass,
+            @NonNull Parcel in) {
+        @SuppressWarnings("unchecked")
+        TimestampedValue<Long> unixEpochTime = in.readParcelable(
+                null /* classLoader */, TimestampedValue.class);
+        TimeSuggestionHelper suggestionHelper =
+                new TimeSuggestionHelper(helpedClass, unixEpochTime);
+        suggestionHelper.mDebugInfo = in.readArrayList(null /* classLoader */, String.class);
+        return suggestionHelper;
+    }
+
+    /** Writes the helper suggestion state to a Parcel. */
+    public void handleWriteToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelable(mUnixEpochTime, 0);
+        dest.writeList(mDebugInfo);
+    }
+
+    /** Parses command line args to create a {@link TimeSuggestionHelper}. */
+    public static TimeSuggestionHelper handleParseCommandLineArg(
+            @NonNull Class<?> helpedClass, @NonNull ShellCommand cmd)
+            throws IllegalArgumentException {
+        Long referenceTimeMillis = null;
+        Long unixEpochTimeMillis = null;
+        String opt;
+        while ((opt = cmd.getNextArg()) != null) {
+            switch (opt) {
+                case "--reference_time": {
+                    referenceTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+                    break;
+                }
+                case "--unix_epoch_time": {
+                    unixEpochTimeMillis = Long.parseLong(cmd.getNextArgRequired());
+                    break;
+                }
+                default: {
+                    throw new IllegalArgumentException("Unknown option: " + opt);
+                }
+            }
+        }
+
+        if (referenceTimeMillis == null) {
+            throw new IllegalArgumentException("No referenceTimeMillis specified.");
+        }
+        if (unixEpochTimeMillis == null) {
+            throw new IllegalArgumentException("No unixEpochTimeMillis specified.");
+        }
+
+        TimestampedValue<Long> timeSignal =
+                new TimestampedValue<>(referenceTimeMillis, unixEpochTimeMillis);
+        TimeSuggestionHelper suggestionHelper = new TimeSuggestionHelper(helpedClass, timeSignal);
+        suggestionHelper.addDebugInfo("Command line injection");
+        return suggestionHelper;
+    }
+
+    /** Prints the command line args needed to create a {@link TimeSuggestionHelper}. */
+    public static void handlePrintCommandLineOpts(
+            @NonNull PrintWriter pw, @NonNull String typeName, @NonNull Class<?> clazz) {
+        pw.printf("%s suggestion options:\n", typeName);
+        pw.println("  --reference_time <elapsed realtime millis>");
+        pw.println("  --unix_epoch_time <Unix epoch time millis>");
+        pw.println();
+        pw.println("See " + clazz.getName() + " for more information");
+    }
+}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5119010..ce21214 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2929,6 +2929,8 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a CDMA telephony stack.
+     *
+     * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma";
@@ -2936,6 +2938,8 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a GSM telephony stack.
+     *
+     * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm";
@@ -2947,6 +2951,9 @@
      * <p>Devices declaring this feature must have an implementation of the
      * {@link android.telephony.TelephonyManager#getAllowedCarriers} and
      * {@link android.telephony.TelephonyManager#setAllowedCarriers}.
+     *
+     * This feature should only be defined if {@link #FEATURE_TELEPHONY_SUBSCRIPTION}
+     * has been defined.
      * @hide
      */
     @SystemApi
@@ -2957,6 +2964,9 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
      * supports embedded subscriptions on eUICCs.
+     *
+     * This feature should only be defined if {@link #FEATURE_TELEPHONY_SUBSCRIPTION}
+     * has been defined.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEPHONY_EUICC = "android.hardware.telephony.euicc";
@@ -2964,6 +2974,9 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
      * supports cell-broadcast reception using the MBMS APIs.
+     *
+     * <p>This feature should only be defined if both {@link #FEATURE_TELEPHONY_SUBSCRIPTION}
+     * and {@link #FEATURE_TELEPHONY_RADIO_ACCESS} have been defined.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEPHONY_MBMS = "android.hardware.telephony.mbms";
@@ -2971,6 +2984,8 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device
      * supports attaching to IMS implementations using the ImsService API in telephony.
+     *
+     * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY_DATA} has been defined.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_TELEPHONY_IMS = "android.hardware.telephony.ims";
@@ -3007,6 +3022,62 @@
             "android.hardware.telephony.ims.singlereg";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports Telecom Service APIs.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELECOM = "android.software.telecom";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports Telephony APIs for calling service.
+     *
+     * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY_RADIO_ACCESS},
+     * {@link #FEATURE_TELEPHONY_SUBSCRIPTION}, and {@link #FEATURE_TELECOM} have been defined.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_CALLING = "android.hardware.telephony.calling";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports Telephony APIs for data service.
+     *
+     * <p>This feature should only be defined if both {@link #FEATURE_TELEPHONY_SUBSCRIPTION}
+     * and {@link #FEATURE_TELEPHONY_RADIO_ACCESS} have been defined.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_DATA = "android.hardware.telephony.data";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports Telephony APIs for SMS and MMS.
+     *
+     * <p>This feature should only be defined if both {@link #FEATURE_TELEPHONY_SUBSCRIPTION}
+     * and {@link #FEATURE_TELEPHONY_RADIO_ACCESS} have been defined.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_MESSAGING = "android.hardware.telephony.messaging";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports Telephony APIs for the radio access.
+     *
+     * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+     * The device supports Telephony APIs for the subscription.
+     *
+     * <p>This feature should only be defined if {@link #FEATURE_TELEPHONY} has been defined.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_TELEPHONY_SUBSCRIPTION =
+            "android.hardware.telephony.subscription";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device is capable of communicating with
      * other devices via ultra wideband.
@@ -3047,7 +3118,9 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The Connection Service API is enabled on the device.
+     * @deprecated use {@link #FEATURE_TELECOM} instead.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
 
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index b3851a5..d24a95d 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -35,7 +35,7 @@
          rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max
          If this is configured as an empty string, the system default will be applied.
     -->
-    <string name="config_tcp_buffers" translatable="false"></string>
+    <string name="config_tcp_buffers" translatable="false">2097152,6291456,16777216,512000,2097152,8388608</string>
     <java-symbol type="string"  name="config_tcp_buffers" />
 
     <!-- What source to use to estimate link upstream and downstream bandwidth capacities.
@@ -109,4 +109,12 @@
     <!-- Telephony qualified networks service class name to bind to by default. -->
     <string name="config_qualified_networks_service_class" translatable="false"></string>
     <java-symbol type="string" name="config_qualified_networks_service_class" />
+
+    <!-- Whether enhanced IWLAN handover check is enabled. If enabled, telephony frameworks
+         will not perform handover if the target transport is out of service, or VoPS not
+         supported. The network will be torn down on the source transport, and will be
+         re-established on the target transport when condition is allowed for bringing up a
+         new network. -->
+    <bool name="config_enhanced_iwlan_handover_check">true</bool>
+    <java-symbol type="bool" name="config_enhanced_iwlan_handover_check" />
 </resources>
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
index c112cbb..6f2366e 100644
--- a/core/tests/PackageInstallerSessions/Android.bp
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -50,7 +50,6 @@
         ":PackageManagerTestAppVersion1",
     ],
 
-    platform_apis: true,
     sdk_version: "core_platform",
     test_suites: ["device-tests"],
 }
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index f87797a..2b34ee2 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -36,7 +36,6 @@
     ],
     test_suites: ["general-tests"],
     sdk_version: "test_current",
-    platform_apis: true,
 }
 
 filegroup {
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 05ec00f..f971af1 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -72,7 +72,6 @@
         "libpowermanagertest_jni",
     ],
 
-    platform_apis: true,
     sdk_version: "core_platform",
     test_suites: ["device-tests"],
 
diff --git a/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
new file mode 100644
index 0000000..90b3305
--- /dev/null
+++ b/core/tests/coretests/src/android/app/time/ExternalTimeSuggestionTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 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.time;
+
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.ShellCommand;
+
+import org.junit.Test;
+
+/**
+ * Tests for non-SDK methods on {@link ExternalTimeSuggestion}.
+ * Also see {@link android.app.time.cts.ExternalTimeSuggestionTest}
+ */
+public class ExternalTimeSuggestionTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noReferenceTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--unix_epoch_time 12345");
+        ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noUnixEpochTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321");
+        ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validSuggestion() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345");
+        ExternalTimeSuggestion expectedSuggestion = new ExternalTimeSuggestion(54321L, 12345L);
+        ExternalTimeSuggestion actualSuggestion =
+                ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_unknownArgument() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+        ExternalTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
index e248010..af403a2 100644
--- a/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
@@ -18,10 +18,12 @@
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
 import org.junit.Test;
@@ -63,4 +65,36 @@
         GnssTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
         assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
     }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noReferenceTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--unix_epoch_time 12345");
+        GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noUnixEpochTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321");
+        GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validSuggestion() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345");
+        TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L);
+        GnssTimeSuggestion expectedSuggestion = new GnssTimeSuggestion(timeSignal);
+        GnssTimeSuggestion actualSuggestion =
+                GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_unknownArgument() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+        GnssTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
 }
diff --git a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
index 750ffa1..94218cd 100644
--- a/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/ManualTimeSuggestionTest.java
@@ -18,10 +18,12 @@
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
 import org.junit.Test;
@@ -63,4 +65,36 @@
         ManualTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
         assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
     }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noReferenceTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--unix_epoch_time 12345");
+        ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noUnixEpochTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321");
+        ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validSuggestion() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345");
+        TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L);
+        ManualTimeSuggestion expectedSuggestion = new ManualTimeSuggestion(timeSignal);
+        ManualTimeSuggestion actualSuggestion =
+                ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_unknownArgument() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+        ManualTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
 }
diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
index b88c36f..0e09dd3 100644
--- a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
@@ -18,10 +18,12 @@
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
 import org.junit.Test;
@@ -63,4 +65,36 @@
         NetworkTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
         assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
     }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noReferenceTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--unix_epoch_time 12345");
+        NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noUnixEpochTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321");
+        NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validSuggestion() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345");
+        TimestampedValue<Long> timeSignal = new TimestampedValue<>(54321L, 12345L);
+        NetworkTimeSuggestion expectedSuggestion = new NetworkTimeSuggestion(timeSignal);
+        NetworkTimeSuggestion actualSuggestion =
+                NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_unknownArgument() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+        NetworkTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
 }
diff --git a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
index cc75579..bb995a8 100644
--- a/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/TelephonyTimeSuggestionTest.java
@@ -18,10 +18,12 @@
 
 import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
 import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+import static android.app.timezonedetector.ShellCommandTestSupport.createShellCommandWithArgsAndOptions;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 
+import android.os.ShellCommand;
 import android.os.TimestampedValue;
 
 import org.junit.Test;
@@ -95,4 +97,45 @@
             assertEquals(suggestion1.getDebugInfo(), rtSuggestion1.getDebugInfo());
         }
     }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noSlotIndex() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--reference_time 54321 --unix_epoch_time 12345");
+        TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noReferenceTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--slot_index 0 --unix_epoch_time 12345");
+        TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_noUnixEpochTime() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--slot_index 0 --reference_time 54321");
+        TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
+
+    @Test
+    public void testParseCommandLineArg_validSuggestion() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--slot_index 0 --reference_time 54321 --unix_epoch_time 12345");
+        TelephonyTimeSuggestion expectedSuggestion =
+                new TelephonyTimeSuggestion.Builder(0)
+                        .setUnixEpochTime(new TimestampedValue<>(54321L, 12345L))
+                        .build();
+        TelephonyTimeSuggestion actualSuggestion =
+                TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+        assertEquals(expectedSuggestion, actualSuggestion);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testParseCommandLineArg_unknownArgument() {
+        ShellCommand testShellCommand = createShellCommandWithArgsAndOptions(
+                "--slot_index 0 --reference_time 54321 --unix_epoch_time 12345 --bad_arg 0");
+        TelephonyTimeSuggestion.parseCommandLineArg(testShellCommand);
+    }
 }
diff --git a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
index 8d8290c..4efaed1 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/ShellCommandTestSupport.java
@@ -26,14 +26,14 @@
 import java.util.List;
 
 /** Utility methods related to {@link ShellCommand} objects used in several tests. */
-final class ShellCommandTestSupport {
+public final class ShellCommandTestSupport {
     private ShellCommandTestSupport() {}
 
-    static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
+    public static ShellCommand createShellCommandWithArgsAndOptions(String argsWithSpaces) {
         return createShellCommandWithArgsAndOptions(Arrays.asList(argsWithSpaces.split(" ")));
     }
 
-    static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
+    public static ShellCommand createShellCommandWithArgsAndOptions(List<String> args) {
         ShellCommand command = mock(ShellCommand.class);
         class ArgProvider {
             private int mCount;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
index 9ad6f3a..6fff52a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreBCWorkaroundProvider.java
@@ -206,6 +206,8 @@
 
         putSignatureImpl("NONEwithECDSA",
                 PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE");
+        putSignatureImpl("Ed25519",
+                PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$Ed25519");
 
         putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
         put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
index 8289671..5216a90 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
@@ -29,7 +29,10 @@
 import java.io.ByteArrayOutputStream;
 import java.security.InvalidKeyException;
 import java.security.SignatureSpi;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Base class for {@link SignatureSpi} providing Android KeyStore backed ECDSA signatures.
@@ -37,6 +40,10 @@
  * @hide
  */
 abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
+    private static final Set<String> ACCEPTED_SIGNING_SCHEMES = Set.of(
+            KeyProperties.KEY_ALGORITHM_EC.toLowerCase(),
+            NamedParameterSpec.ED25519.getName().toLowerCase(),
+            "eddsa");
 
     public final static class NONE extends AndroidKeyStoreECDSASignatureSpi {
         public NONE() {
@@ -114,6 +121,18 @@
         }
     }
 
+    public static final class Ed25519 extends AndroidKeyStoreECDSASignatureSpi {
+        public Ed25519() {
+            // Ed25519 uses an internal digest system.
+            super(KeymasterDefs.KM_DIGEST_NONE);
+        }
+
+        @Override
+        protected String getAlgorithm() {
+            return NamedParameterSpec.ED25519.getName();
+        }
+    }
+
     public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
         public SHA1() {
             super(KeymasterDefs.KM_DIGEST_SHA1);
@@ -174,9 +193,10 @@
 
     @Override
     protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
-        if (!KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
+        if (!ACCEPTED_SIGNING_SCHEMES.contains(key.getAlgorithm().toLowerCase())) {
             throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
-                    + ". Only" + KeyProperties.KEY_ALGORITHM_EC + " supported");
+                    + ". Only" + Arrays.toString(ACCEPTED_SIGNING_SCHEMES.stream().toArray())
+                    + " supported");
         }
 
         long keySizeBits = -1;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java
new file mode 100644
index 0000000..4855ad0
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java
@@ -0,0 +1,46 @@
+/*
+ * 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.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.KeyDescriptor;
+
+import java.security.PrivateKey;
+import java.security.interfaces.EdECKey;
+import java.security.spec.NamedParameterSpec;
+
+/**
+ * EdEC private key (instance of {@link PrivateKey} and {@link EdECKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreEdECPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey {
+    public AndroidKeyStoreEdECPrivateKey(
+            @NonNull KeyDescriptor descriptor, long keyId,
+            @NonNull Authorization[] authorizations,
+            @NonNull String algorithm,
+            @NonNull KeyStoreSecurityLevel securityLevel) {
+        super(descriptor, keyId, authorizations, algorithm, securityLevel);
+    }
+
+    @Override
+    public NamedParameterSpec getParams() {
+        return NamedParameterSpec.ED25519;
+    }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java
new file mode 100644
index 0000000..642e088
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java
@@ -0,0 +1,145 @@
+/*
+ * 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.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import java.math.BigInteger;
+import java.security.interfaces.EdECPublicKey;
+import java.security.spec.EdECPoint;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * {@link EdECPublicKey} backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreEdECPublicKey extends AndroidKeyStorePublicKey
+        implements EdECPublicKey {
+    /**
+     * DER sequence, as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-4 and
+     * https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.
+     * SEQUENCE (2 elem)
+     *  SEQUENCE (1 elem)
+     *    OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm)
+     *    as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-3
+     *  BIT STRING (256 bit) as defined in
+     *  https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.2
+     */
+    private static final byte[] DER_KEY_PREFIX = new byte[] {
+            0x30,
+            0x2a,
+            0x30,
+            0x05,
+            0x06,
+            0x03,
+            0x2b,
+            0x65,
+            0x70,
+            0x03,
+            0x21,
+            0x00,
+    };
+    private static final int ED25519_KEY_SIZE_BYTES = 32;
+
+    private byte[] mEncodedKey;
+    private EdECPoint mPoint;
+
+    public AndroidKeyStoreEdECPublicKey(
+            @NonNull KeyDescriptor descriptor,
+            @NonNull KeyMetadata metadata,
+            @NonNull String algorithm,
+            @NonNull KeyStoreSecurityLevel iSecurityLevel,
+            @NonNull byte[] encodedKey) {
+        super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel);
+        mEncodedKey = encodedKey;
+
+        int preambleLength = matchesPreamble(DER_KEY_PREFIX, encodedKey);
+        if (preambleLength == 0) {
+            throw new IllegalArgumentException("Key size is not correct size");
+        }
+
+        mPoint = pointFromKeyByteArray(
+                Arrays.copyOfRange(encodedKey, preambleLength, encodedKey.length));
+    }
+
+    @Override
+    AndroidKeyStorePrivateKey getPrivateKey() {
+        return new AndroidKeyStoreEdECPrivateKey(
+                getUserKeyDescriptor(),
+                getKeyIdDescriptor().nspace,
+                getAuthorizations(),
+                "EdDSA",
+                getSecurityLevel());
+    }
+
+    @Override
+    public NamedParameterSpec getParams() {
+        return NamedParameterSpec.ED25519;
+    }
+
+    @Override
+    public EdECPoint getPoint() {
+        return mPoint;
+    }
+
+    private static int matchesPreamble(byte[] preamble, byte[] encoded) {
+        if (encoded.length != (preamble.length + ED25519_KEY_SIZE_BYTES)) {
+            return 0;
+        }
+        if (Arrays.compare(preamble, Arrays.copyOf(encoded, preamble.length)) != 0) {
+            return 0;
+        }
+        return preamble.length;
+    }
+
+    private static EdECPoint pointFromKeyByteArray(byte[] coordinates) {
+        Objects.requireNonNull(coordinates);
+
+        // Oddity of the key is the most-significant bit of the last byte.
+        boolean isOdd = (0x80 & coordinates[coordinates.length - 1]) != 0;
+        // Zero out the oddity bit.
+        coordinates[coordinates.length - 1] &= (byte) 0x7f;
+        // Representation of Y is in little-endian, according to rfc8032 section-3.1.
+        reverse(coordinates);
+        // The integer representing Y starts from the first bit in the coordinates array.
+        BigInteger y = new BigInteger(1, coordinates);
+        return new EdECPoint(isOdd, y);
+    }
+
+    private static void reverse(byte[] coordinateArray) {
+        int start = 0;
+        int end = coordinateArray.length - 1;
+        while (start < end) {
+            byte tmp = coordinateArray[start];
+            coordinateArray[start] = coordinateArray[end];
+            coordinateArray[end] = tmp;
+            start++;
+            end--;
+        }
+    }
+
+    @Override
+    public byte[] getEncoded() {
+        return mEncodedKey.clone();
+    }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
index fc963a8..b1338d1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
@@ -61,6 +61,17 @@
         }
     }
 
+    /**
+     * X25519 key agreement support.
+     *
+     * @hide
+     */
+    public static class XDH extends AndroidKeyStoreKeyAgreementSpi {
+        public XDH() {
+            super(Algorithm.EC);
+        }
+    }
+
     private final int mKeymintAlgorithm;
 
     // Fields below are populated by engineInit and should be preserved after engineDoFinal.
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index d31499e..9947d34 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -104,6 +104,7 @@
 
         // javax.crypto.KeyAgreement
         put("KeyAgreement.ECDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$ECDH");
+        put("KeyAgreement.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyAgreementSpi$XDH");
 
         // java.security.SecretKeyFactory
         putSecretKeyFactoryImpl("AES");
@@ -224,7 +225,6 @@
 
         String jcaKeyAlgorithm = publicKey.getAlgorithm();
 
-        KeyStoreSecurityLevel securityLevel = iSecurityLevel;
         if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {
             return new AndroidKeyStoreECPublicKey(descriptor, metadata,
                     iSecurityLevel, (ECPublicKey) publicKey);
@@ -232,11 +232,12 @@
             return new AndroidKeyStoreRSAPublicKey(descriptor, metadata,
                     iSecurityLevel, (RSAPublicKey) publicKey);
         } else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) {
-            //TODO(b/214203951) missing classes in conscrypt
-            throw new ProviderException("Curve " + ED25519_OID + " not supported yet");
+            final byte[] publicKeyEncoded = publicKey.getEncoded();
+            return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID,
+                    iSecurityLevel, publicKeyEncoded);
         } else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
-            //TODO(b/214203951) missing classes in conscrypt
-            throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet");
+            return new AndroidKeyStoreXDHPublicKey(descriptor, metadata, X25519_ALIAS,
+                    iSecurityLevel, publicKey.getEncoded());
         } else {
             throw new ProviderException("Unsupported Android Keystore public key algorithm: "
                     + jcaKeyAlgorithm);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java
new file mode 100644
index 0000000..42589640
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPrivateKey.java
@@ -0,0 +1,47 @@
+/*
+ * 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.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.KeyDescriptor;
+
+import java.security.PrivateKey;
+import java.security.interfaces.EdECKey;
+import java.security.spec.NamedParameterSpec;
+
+/**
+ * X25519 Private Key backed by Keystore.
+ * instance of {@link PrivateKey} and {@link EdECKey}
+ *
+ * @hide
+ */
+public class AndroidKeyStoreXDHPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey {
+    public AndroidKeyStoreXDHPrivateKey(
+            @NonNull KeyDescriptor descriptor, long keyId,
+            @NonNull Authorization[] authorizations,
+            @NonNull String algorithm,
+            @NonNull KeyStoreSecurityLevel securityLevel) {
+        super(descriptor, keyId, authorizations, algorithm, securityLevel);
+    }
+
+    @Override
+    public NamedParameterSpec getParams() {
+        return NamedParameterSpec.X25519;
+    }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java
new file mode 100644
index 0000000..9f3df3d
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java
@@ -0,0 +1,120 @@
+/*
+ * 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.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import java.math.BigInteger;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+
+/**
+ * {@link XECPublicKey} backed by keystore.
+ * This class re-implements Conscrypt's OpenSSLX25519PublicKey. The reason is that
+ * OpenSSLX25519PublicKey does not implement XECPublicKey and is not a part of Conscrypt's public
+ * interface so it cannot be referred to.
+ *
+ * So the functionality is duplicated here until (likely Android U) one of the things mentioned
+ * above is fixed.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreXDHPublicKey extends AndroidKeyStorePublicKey implements XECPublicKey {
+    private static final byte[] X509_PREAMBLE = new byte[] {
+            0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00,
+    };
+
+    private static final byte[] X509_PREAMBLE_WITH_NULL = new byte[] {
+            0x30, 0x2C, 0x30, 0x07, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x05, 0x00, 0x03, 0x21, 0x00,
+    };
+
+    private static final int X25519_KEY_SIZE_BYTES = 32;
+
+    private final byte[] mEncodedKey;
+    private final int mPreambleLength;
+
+    public AndroidKeyStoreXDHPublicKey(
+            @NonNull KeyDescriptor descriptor,
+            @NonNull KeyMetadata metadata,
+            @NonNull String algorithm,
+            @NonNull KeyStoreSecurityLevel iSecurityLevel,
+            @NonNull byte[] encodedKey) {
+        super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel);
+        mEncodedKey = encodedKey;
+        if (mEncodedKey == null) {
+            throw new IllegalArgumentException("empty encoded key.");
+        }
+
+        mPreambleLength = matchesPreamble(X509_PREAMBLE, mEncodedKey) | matchesPreamble(
+                X509_PREAMBLE_WITH_NULL, mEncodedKey);
+        if (mPreambleLength == 0) {
+            throw new IllegalArgumentException("Key size is not correct size");
+        }
+    }
+
+    private static int matchesPreamble(byte[] preamble, byte[] encoded) {
+        if (encoded.length != (preamble.length + X25519_KEY_SIZE_BYTES)) {
+            return 0;
+        }
+
+        if (Arrays.compare(preamble, 0, preamble.length, encoded, 0, preamble.length) != 0) {
+            return 0;
+        }
+        return preamble.length;
+    }
+
+    @Override
+    AndroidKeyStorePrivateKey getPrivateKey() {
+        return new AndroidKeyStoreXDHPrivateKey(
+                getUserKeyDescriptor(),
+                getKeyIdDescriptor().nspace,
+                getAuthorizations(),
+                "x25519",
+                getSecurityLevel());
+    }
+
+    @Override
+    public BigInteger getU() {
+        return new BigInteger(Arrays.copyOfRange(mEncodedKey, mPreambleLength, mEncodedKey.length));
+    }
+
+    @Override
+    public byte[] getEncoded() {
+        return mEncodedKey.clone();
+    }
+
+    @Override
+    public String getAlgorithm() {
+        return "XDH";
+    }
+
+    @Override
+    public String getFormat() {
+        return "x.509";
+    }
+
+    @Override
+    public AlgorithmParameterSpec getParams() {
+        return NamedParameterSpec.X25519;
+    }
+}
+
diff --git a/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java
new file mode 100644
index 0000000..5bd5797
--- /dev/null
+++ b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.security.keystore2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.math.BigInteger;
+import java.util.Base64;
+
+@RunWith(AndroidJUnit4.class)
+public class AndroidKeyStoreEdECPublicKeyTest {
+    private static KeyDescriptor descriptor() {
+        final KeyDescriptor keyDescriptor = new KeyDescriptor();
+        keyDescriptor.alias = "key";
+        keyDescriptor.blob = null;
+        keyDescriptor.domain = Domain.APP;
+        keyDescriptor.nspace = -1;
+        return keyDescriptor;
+    }
+
+    private static KeyMetadata metadata(byte[] cert, byte[] certChain) {
+        KeyMetadata metadata = new KeyMetadata();
+        metadata.authorizations = new Authorization[0];
+        metadata.certificate = cert;
+        metadata.certificateChain = certChain;
+        metadata.key = descriptor();
+        metadata.modificationTimeMs = 0;
+        metadata.keySecurityLevel = 1;
+        return metadata;
+    }
+
+    @Mock
+    private KeyStoreSecurityLevel mKeystoreSecurityLevel;
+
+    private static class EdECTestVector {
+        public final byte[] encodedKeyBytes;
+        public final boolean isOdd;
+        public final BigInteger yValue;
+
+        EdECTestVector(String b64KeyBytes, boolean isOdd, String yValue) {
+            this.encodedKeyBytes = Base64.getDecoder().decode(b64KeyBytes);
+            this.isOdd = isOdd;
+            this.yValue = new BigInteger(yValue);
+        }
+    }
+
+    private static final EdECTestVector[] ED_EC_TEST_VECTORS = new EdECTestVector[]{
+            new EdECTestVector("MCowBQYDK2VwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo=",
+                    false,
+                    "19147682157189290216699341180089409126316261024914226007941553249095116672780"
+                    ),
+            new EdECTestVector("MCowBQYDK2VwAyEA/0E1IRNzGj85Ot/TPeXqifkqTkdk4voleH0hIq59D9w=",
+                    true,
+                    "41640152188550647350742178040529506688513911269563908889464821205156322689535"
+                    ),
+            new EdECTestVector("MCowBQYDK2VwAyEAunOvGuenetl9GQSXGVo5L3RIr4OOIpFIv/Zre8qTc/8=",
+                    true,
+                    "57647939198144376128225770417635248407428273266444593100194116168980378907578"
+                    ),
+            new EdECTestVector("MCowBQYDK2VwAyEA2hHqaZ5IolswN1Yd58Y4hzhmUMCCqc4PW5A/SFLmTX8=",
+                    false,
+                    "57581368614046789120409806291852629847774713088410311752049592044694364885466"
+                    ),
+    };
+
+    @Test
+    public void testParsingOfValidKeys() {
+        for (EdECTestVector testVector : ED_EC_TEST_VECTORS) {
+            AndroidKeyStoreEdECPublicKey pkey = new AndroidKeyStoreEdECPublicKey(descriptor(),
+                    metadata(null, null), "EdDSA", mKeystoreSecurityLevel,
+                    testVector.encodedKeyBytes);
+
+            assertEquals(pkey.getPoint().isXOdd(), testVector.isOdd);
+            assertEquals(pkey.getPoint().getY(), testVector.yValue);
+        }
+    }
+
+    @Test
+    public void testFailedParsingOfKeysWithDifferentOid() {
+        final byte[] testVectorWithIncorrectOid = Base64.getDecoder().decode(
+                "MCowBQYDLGVwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo=");
+        assertThrows("OID should be unrecognized", IllegalArgumentException.class,
+                () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA",
+                        mKeystoreSecurityLevel, testVectorWithIncorrectOid));
+    }
+
+    @Test
+    public void testFailedParsingOfKeysWithWrongSize() {
+        final byte[] testVectorWithIncorrectKeySize = Base64.getDecoder().decode(
+        "MCwwBQYDK2VwAyMADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSrOzg==");
+        assertThrows("Key length should be invalid", IllegalArgumentException.class,
+                () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA",
+                        mKeystoreSecurityLevel, testVectorWithIncorrectKeySize));
+    }
+}
+
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 050ae72..66e2c41 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -230,9 +230,10 @@
     /**
      * A key describing the log session ID for MediaCodec. The log session ID is a random 32-byte
      * hexadecimal string that is used to associate metrics from multiple media codec instances
-     * to the same playback or recording session.
+     * to the same playback or recording session. The value is created as
+     * {@link android.media.metrics.LogSessionId LogSessionId}. Sessions are created in
+     * {@link android.media.metrics.MediaMetricsManager MediaMetricsManager}.
      * The associated value is a string.
-     * @hide
      */
     public static final String LOG_SESSION_ID = "log-session-id";
 
diff --git a/packages/SettingsLib/ActionBarShadow/Android.bp b/packages/SettingsLib/ActionBarShadow/Android.bp
index 4a07d49..2c86201 100644
--- a/packages/SettingsLib/ActionBarShadow/Android.bp
+++ b/packages/SettingsLib/ActionBarShadow/Android.bp
@@ -20,4 +20,8 @@
 
     sdk_version: "system_current",
     min_sdk_version: "28",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/AppPreference/Android.bp b/packages/SettingsLib/AppPreference/Android.bp
index 1817a77..122f606 100644
--- a/packages/SettingsLib/AppPreference/Android.bp
+++ b/packages/SettingsLib/AppPreference/Android.bp
@@ -20,4 +20,8 @@
     ],
     sdk_version: "system_current",
     min_sdk_version: "21",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/BarChartPreference/Android.bp b/packages/SettingsLib/BarChartPreference/Android.bp
index 4f65373..5c5da98 100644
--- a/packages/SettingsLib/BarChartPreference/Android.bp
+++ b/packages/SettingsLib/BarChartPreference/Android.bp
@@ -19,4 +19,8 @@
 
     sdk_version: "system_current",
     min_sdk_version: "21",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/HelpUtils/Android.bp b/packages/SettingsLib/HelpUtils/Android.bp
index 5826047..aea51b1 100644
--- a/packages/SettingsLib/HelpUtils/Android.bp
+++ b/packages/SettingsLib/HelpUtils/Android.bp
@@ -19,4 +19,8 @@
 
     sdk_version: "system_current",
     min_sdk_version: "21",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/LayoutPreference/Android.bp b/packages/SettingsLib/LayoutPreference/Android.bp
index 8a4e53d..aaffdc9 100644
--- a/packages/SettingsLib/LayoutPreference/Android.bp
+++ b/packages/SettingsLib/LayoutPreference/Android.bp
@@ -14,9 +14,13 @@
     resource_dirs: ["res"],
 
     static_libs: [
-          "androidx.preference_preference",
+        "androidx.preference_preference",
     ],
 
     sdk_version: "system_current",
     min_sdk_version: "21",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/ProgressBar/Android.bp b/packages/SettingsLib/ProgressBar/Android.bp
index b5bc8f7..fb3c4e6 100644
--- a/packages/SettingsLib/ProgressBar/Android.bp
+++ b/packages/SettingsLib/ProgressBar/Android.bp
@@ -15,4 +15,8 @@
 
     sdk_version: "system_current",
     min_sdk_version: "21",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/RestrictedLockUtils/Android.bp b/packages/SettingsLib/RestrictedLockUtils/Android.bp
index c0623ed..a7dcf8d 100644
--- a/packages/SettingsLib/RestrictedLockUtils/Android.bp
+++ b/packages/SettingsLib/RestrictedLockUtils/Android.bp
@@ -19,4 +19,8 @@
 
     sdk_version: "system_current",
     min_sdk_version: "21",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/SearchWidget/Android.bp b/packages/SettingsLib/SearchWidget/Android.bp
index b7367b4..5aaee2a 100644
--- a/packages/SettingsLib/SearchWidget/Android.bp
+++ b/packages/SettingsLib/SearchWidget/Android.bp
@@ -14,4 +14,8 @@
     resource_dirs: ["res"],
     sdk_version: "system_current",
     min_sdk_version: "21",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.permission",
+    ],
 }
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 73459c2..da01f62 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -13,13 +13,14 @@
     resource_dirs: ["res"],
 
     static_libs: [
-            "androidx.preference_preference",
-        ],
+        "androidx.preference_preference",
+    ],
 
     sdk_version: "system_current",
     min_sdk_version: "21",
     apex_available: [
         "//apex_available:platform",
         "com.android.cellbroadcast",
+        "com.android.permission",
     ],
 }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ff4c2c6..c4d4261 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -478,6 +478,12 @@
     <uses-permission android:name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
     <uses-permission android:name="android.permission.SUGGEST_EXTERNAL_TIME" />
 
+    <!-- Permissions used for manual testing of time detection behavior. -->
+    <uses-permission android:name="android.permission.SUGGEST_MANUAL_TIME" />
+    <uses-permission android:name="android.permission.SUGGEST_TELEPHONY_TIME" />
+    <uses-permission android:name="android.permission.SUGGEST_NETWORK_TIME" />
+    <uses-permission android:name="android.permission.SUGGEST_GNSS_TIME" />
+
     <!-- Permission required for CTS test - android.server.biometrics -->
     <uses-permission android:name="android.permission.USE_BIOMETRIC" />
 
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 9676a57..91c7a24 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -376,7 +376,7 @@
             Log.w(TAG, String.format("onActiveChanged(%d,%d,%s,%s,%d,%d)", code, uid, packageName,
                     Boolean.toString(active), attributionChainId, attributionFlags));
         }
-        if (attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE
+        if (active && attributionChainId != AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE
                 && attributionFlags != AppOpsManager.ATTRIBUTION_FLAGS_NONE
                 && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR) == 0
                 && (attributionFlags & AppOpsManager.ATTRIBUTION_FLAG_TRUSTED) == 0) {
diff --git a/services/core/OWNERS b/services/core/OWNERS
deleted file mode 100644
index 88d0b61..0000000
--- a/services/core/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file Android.bp = file:platform/build/soong:/OWNERS
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 406ff9b..a81699f 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1202,8 +1202,11 @@
                     break;
                 case MSG_L_SET_BT_ACTIVE_DEVICE:
                     synchronized (mDeviceStateLock) {
-                        mDeviceInventory.onSetBtActiveDevice((BtDeviceInfo) msg.obj,
-                                mAudioService.getBluetoothContextualVolumeStream());
+                        BtDeviceInfo btInfo = (BtDeviceInfo) msg.obj;
+                        mDeviceInventory.onSetBtActiveDevice(btInfo,
+                                (btInfo.mProfile != BluetoothProfile.LE_AUDIO || btInfo.mIsLeOutput)
+                                        ? mAudioService.getBluetoothContextualVolumeStream()
+                                        : AudioSystem.STREAM_DEFAULT);
                     }
                     break;
                 case MSG_BT_HEADSET_CNCT_FAILED:
diff --git a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
index 28c7cad..ab3b250 100644
--- a/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
+++ b/services/core/java/com/android/server/clipboard/EmulatorClipboardMonitor.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.content.ClipData;
+import android.os.PersistableBundle;
 import android.os.SystemProperties;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -25,6 +26,7 @@
 import android.system.VmSocketAddress;
 import android.util.Slog;
 
+import java.io.EOFException;
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
 import java.net.SocketException;
@@ -58,11 +60,11 @@
         return mPipe;
     }
 
-    private synchronized boolean openPipe() {
-        if (mPipe != null) {
-            return true;
-        }
+    private synchronized void setPipeFD(final FileDescriptor fd) {
+        mPipe = fd;
+    }
 
+    private static FileDescriptor openPipeImpl() {
         try {
             final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0);
 
@@ -70,39 +72,42 @@
                 Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST));
 
                 final byte[] handshake = createOpenHandshake();
-                Os.write(fd, handshake, 0, handshake.length);
-                mPipe = fd;
-                return true;
+                writeFully(fd, handshake, 0, handshake.length);
+                return fd;
             } catch (ErrnoException | SocketException | InterruptedIOException e) {
                 Os.close(fd);
             }
         } catch (ErrnoException e) {
         }
 
-        return false;
+        return null;
     }
 
-    private synchronized void closePipe() {
-        try {
-            final FileDescriptor fd = mPipe;
-            mPipe = null;
-            if (fd != null) {
-                Os.close(fd);
-            }
-        } catch (ErrnoException ignore) {
+    private static FileDescriptor openPipe() throws InterruptedException {
+        FileDescriptor fd = openPipeImpl();
+
+        // There's no guarantee that QEMU pipes will be ready at the moment
+        // this method is invoked. We simply try to get the pipe open and
+        // retry on failure indefinitely.
+        while (fd == null) {
+            Thread.sleep(100);
+            fd = openPipeImpl();
         }
+
+        return fd;
     }
 
-    private byte[] receiveMessage() throws ErrnoException, InterruptedIOException {
+    private static byte[] receiveMessage(final FileDescriptor fd) throws ErrnoException,
+            InterruptedIOException, EOFException {
         final byte[] lengthBits = new byte[4];
-        Os.read(mPipe, lengthBits, 0, lengthBits.length);
+        readFully(fd, lengthBits, 0, lengthBits.length);
 
         final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
         bb.order(ByteOrder.LITTLE_ENDIAN);
         final int msgLen = bb.getInt();
 
         final byte[] msg = new byte[msgLen];
-        Os.read(mPipe, msg, 0, msg.length);
+        readFully(fd, msg, 0, msg.length);
 
         return msg;
     }
@@ -115,35 +120,46 @@
         bb.order(ByteOrder.LITTLE_ENDIAN);
         bb.putInt(msg.length);
 
-        Os.write(fd, lengthBits, 0, lengthBits.length);
-        Os.write(fd, msg, 0, msg.length);
+        writeFully(fd, lengthBits, 0, lengthBits.length);
+        writeFully(fd, msg, 0, msg.length);
     }
 
     EmulatorClipboardMonitor(final Consumer<ClipData> setAndroidClipboard) {
         this.mHostMonitorThread = new Thread(() -> {
+            FileDescriptor fd = null;
+
             while (!Thread.interrupted()) {
                 try {
-                    // There's no guarantee that QEMU pipes will be ready at the moment
-                    // this method is invoked. We simply try to get the pipe open and
-                    // retry on failure indefinitely.
-                    while (!openPipe()) {
-                        Thread.sleep(100);
+                    if (fd == null) {
+                        fd = openPipe();
+                        setPipeFD(fd);
                     }
 
-                    final byte[] receivedData = receiveMessage();
+                    final byte[] receivedData = receiveMessage(fd);
 
                     final String str = new String(receivedData);
                     final ClipData clip = new ClipData("host clipboard",
                                                        new String[]{"text/plain"},
                                                        new ClipData.Item(str));
+                    final PersistableBundle bundle = new PersistableBundle();
+                    bundle.putBoolean("com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY", true);
+                    clip.getDescription().setExtras(bundle);
 
                     if (LOG_CLIBOARD_ACCESS) {
                         Slog.i(TAG, "Setting the guest clipboard to '" + str + "'");
                     }
                     setAndroidClipboard.accept(clip);
-                } catch (ErrnoException | InterruptedIOException e) {
-                    closePipe();
-                } catch (InterruptedException | IllegalArgumentException e) {
+                } catch (ErrnoException | EOFException | InterruptedIOException
+                         | InterruptedException e) {
+                    setPipeFD(null);
+
+                    try {
+                        Os.close(fd);
+                    } catch (ErrnoException e2) {
+                        // ignore
+                    }
+
+                    fd = null;
                 }
             }
         });
@@ -153,33 +169,70 @@
 
     @Override
     public void accept(final @Nullable ClipData clip) {
+        final FileDescriptor fd = getPipeFD();
+        if (fd != null) {
+            setHostClipboard(fd, getClipString(clip));
+        }
+    }
+
+    private String getClipString(final @Nullable ClipData clip) {
         if (clip == null) {
-            setHostClipboardImpl("");
-        } else if (clip.getItemCount() > 0) {
-            final CharSequence text = clip.getItemAt(0).getText();
-            if (text != null) {
-                setHostClipboardImpl(text.toString());
+            return "";
+        }
+
+        if (clip.getItemCount() == 0) {
+            return "";
+        }
+
+        final CharSequence text = clip.getItemAt(0).getText();
+        if (text == null) {
+            return "";
+        }
+
+        return text.toString();
+    }
+
+    private static void setHostClipboard(final FileDescriptor fd, final String value) {
+        Thread t = new Thread(() -> {
+            if (LOG_CLIBOARD_ACCESS) {
+                Slog.i(TAG, "Setting the host clipboard to '" + value + "'");
+            }
+
+            try {
+                sendMessage(fd, value.getBytes());
+            } catch (ErrnoException | InterruptedIOException e) {
+                Slog.e(TAG, "Failed to set host clipboard " + e.getMessage());
+            } catch (IllegalArgumentException e) {
+            }
+        });
+        t.start();
+    }
+
+    private static void readFully(final FileDescriptor fd,
+                                  final byte[] buf, int offset, int size)
+                                  throws ErrnoException, InterruptedIOException, EOFException {
+        while (size > 0) {
+            final int r = Os.read(fd, buf, offset, size);
+            if (r > 0) {
+                offset += r;
+                size -= r;
+            } else {
+                throw new EOFException();
             }
         }
     }
 
-    private void setHostClipboardImpl(final String value) {
-        final FileDescriptor pipeFD = getPipeFD();
-
-        if (pipeFD != null) {
-            Thread t = new Thread(() -> {
-                if (LOG_CLIBOARD_ACCESS) {
-                    Slog.i(TAG, "Setting the host clipboard to '" + value + "'");
-                }
-
-                try {
-                    sendMessage(pipeFD, value.getBytes());
-                } catch (ErrnoException | InterruptedIOException e) {
-                    Slog.e(TAG, "Failed to set host clipboard " + e.getMessage());
-                } catch (IllegalArgumentException e) {
-                }
-            });
-            t.start();
+    private static void writeFully(final FileDescriptor fd,
+                                   final byte[] buf, int offset, int size)
+                                   throws ErrnoException, InterruptedIOException {
+        while (size > 0) {
+            final int r = Os.write(fd, buf, offset, size);
+            if (r > 0) {
+                offset += r;
+                size -= r;
+            } else {
+                throw new ErrnoException("write", OsConstants.EIO);
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index d07f151..f0f1870 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1621,11 +1621,19 @@
     }
 
     // Note: Return type guarantees results are deduped and sorted, which callers require.
+    // This method also adds the SDK sandbox UIDs corresponding to the applications by default,
+    // since apps are generally not aware of them, yet they should follow the VPN configuration
+    // of the app they belong to.
     private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) {
         SortedSet<Integer> uids = new TreeSet<>();
         for (String app : packageNames) {
             int uid = getAppUid(app, userId);
             if (uid != -1) uids.add(uid);
+            // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
+            // ConnectivityServiceTest.
+            if (Process.isApplicationUid(uid) && SdkLevel.isAtLeastT()) {
+                uids.add(Process.toSdkSandboxUid(uid));
+            }
         }
         return uids;
     }
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 7649958..9d26351 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -22,6 +22,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
+import android.os.Build;
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.SystemClock;
@@ -166,6 +167,11 @@
         mWakeLock.release();
     }
 
+    @Override
+    public boolean deviceHasY2038Issue() {
+        return Build.SUPPORTED_32_BIT_ABIS.length > 0;
+    }
+
     private void checkWakeLockHeld() {
         if (!mWakeLock.isHeld()) {
             Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " not held");
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
index 721986b..cc5e6fe 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorShellCommand.java
@@ -17,14 +17,26 @@
 
 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
 import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SERVICE_NAME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_EXTERNAL_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_GNSS_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_MANUAL_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_NETWORK_TIME;
+import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SUGGEST_TELEPHONY_TIME;
 import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME;
 
 import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE;
 import static com.android.server.timedetector.ServerFlags.KEY_TIME_DETECTOR_ORIGIN_PRIORITIES_OVERRIDE;
 
+import android.app.time.ExternalTimeSuggestion;
+import android.app.timedetector.GnssTimeSuggestion;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
+import android.app.timedetector.TelephonyTimeSuggestion;
 import android.os.ShellCommand;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 /** Implements the shell command interface for {@link TimeDetectorService}. */
 class TimeDetectorShellCommand extends ShellCommand {
@@ -44,6 +56,16 @@
         switch (cmd) {
             case SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED:
                 return runIsAutoDetectionEnabled();
+            case SHELL_COMMAND_SUGGEST_MANUAL_TIME:
+                return runSuggestManualTime();
+            case SHELL_COMMAND_SUGGEST_TELEPHONY_TIME:
+                return runSuggestTelephonyTime();
+            case SHELL_COMMAND_SUGGEST_NETWORK_TIME:
+                return runSuggestNetworkTime();
+            case SHELL_COMMAND_SUGGEST_GNSS_TIME:
+                return runSuggestGnssTime();
+            case SHELL_COMMAND_SUGGEST_EXTERNAL_TIME:
+                return runSuggestExternalTime();
             default: {
                 return handleDefaultCommands(cmd);
             }
@@ -59,6 +81,53 @@
         return 0;
     }
 
+    private int runSuggestManualTime() {
+        return runSuggestTime(
+                () -> ManualTimeSuggestion.parseCommandLineArg(this),
+                mInterface::suggestManualTime);
+    }
+
+    private int runSuggestTelephonyTime() {
+        return runSuggestTime(
+                () -> TelephonyTimeSuggestion.parseCommandLineArg(this),
+                mInterface::suggestTelephonyTime);
+    }
+
+    private int runSuggestNetworkTime() {
+        return runSuggestTime(
+                () -> NetworkTimeSuggestion.parseCommandLineArg(this),
+                mInterface::suggestNetworkTime);
+    }
+
+    private int runSuggestGnssTime() {
+        return runSuggestTime(
+                () -> GnssTimeSuggestion.parseCommandLineArg(this),
+                mInterface::suggestGnssTime);
+    }
+
+    private int runSuggestExternalTime() {
+        return runSuggestTime(
+                () -> ExternalTimeSuggestion.parseCommandLineArg(this),
+                mInterface::suggestExternalTime);
+    }
+
+    private <T> int runSuggestTime(Supplier<T> suggestionParser, Consumer<T> invoker) {
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            T suggestion = suggestionParser.get();
+            if (suggestion == null) {
+                pw.println("Error: suggestion not specified");
+                return 1;
+            }
+            invoker.accept(suggestion);
+            pw.println("Suggestion " + suggestion + " injected.");
+            return 0;
+        } catch (RuntimeException e) {
+            pw.println(e);
+            return 1;
+        }
+    }
+
     @Override
     public void onHelp() {
         final PrintWriter pw = getOutPrintWriter();
@@ -68,6 +137,22 @@
         pw.printf("  %s\n", SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED);
         pw.printf("    Prints true/false according to the automatic time detection setting.\n");
         pw.println();
+        pw.printf("  %s <manual suggestion opts>\n", SHELL_COMMAND_SUGGEST_MANUAL_TIME);
+        pw.printf("  %s <telephony suggestion opts>\n", SHELL_COMMAND_SUGGEST_TELEPHONY_TIME);
+        pw.printf("  %s <network suggestion opts>\n", SHELL_COMMAND_SUGGEST_NETWORK_TIME);
+        pw.printf("  %s <gnss suggestion opts>\n", SHELL_COMMAND_SUGGEST_GNSS_TIME);
+        pw.printf("  %s <external suggestion opts>\n", SHELL_COMMAND_SUGGEST_EXTERNAL_TIME);
+        pw.println();
+        ManualTimeSuggestion.printCommandLineOpts(pw);
+        pw.println();
+        TelephonyTimeSuggestion.printCommandLineOpts(pw);
+        pw.println();
+        NetworkTimeSuggestion.printCommandLineOpts(pw);
+        pw.println();
+        GnssTimeSuggestion.printCommandLineOpts(pw);
+        pw.println();
+        ExternalTimeSuggestion.printCommandLineOpts(pw);
+        pw.println();
         pw.printf("This service is also affected by the following device_config flags in the"
                 + " %s namespace:\n", NAMESPACE_SYSTEM_TIME);
         pw.printf("  %s\n", KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index ae4d46c..33ab104 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -85,6 +85,9 @@
      */
     private static final int KEEP_SUGGESTION_HISTORY_SIZE = 10;
 
+    /** The value in Unix epoch milliseconds of the Y2038 issue. */
+    private static final long Y2038_LIMIT_IN_MILLIS = 1000L * Integer.MAX_VALUE;
+
     /**
      * A log that records the decisions / decision metadata that affected the device's system clock
      * time. This is logged in bug reports to assist with debugging issues with detection.
@@ -185,6 +188,12 @@
 
         /** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
         void releaseWakeLock();
+
+        /**
+         * Returns {@code true} if the device may be at risk of time_t overflow (because bionic
+         * defines time_t as a 32-bit signed integer for 32-bit processes).
+         */
+        boolean deviceHasY2038Issue();
     }
 
     static TimeDetectorStrategy create(
@@ -333,6 +342,7 @@
                         .mapToObj(TimeDetectorStrategy::originToString)
                         .collect(joining(",", "[", "]"));
         ipw.println("mEnvironment.autoOriginPriorities()=" + priorities);
+        ipw.println("mEnvironment.deviceHasY2038Issue()=" + mEnvironment.deviceHasY2038Issue());
 
         ipw.println("Time change log:");
         ipw.increaseIndent(); // level 2
@@ -413,6 +423,16 @@
                     + ", suggestion=" + suggestion);
             return false;
         }
+
+        if (newUnixEpochTime.getValue() > Y2038_LIMIT_IN_MILLIS
+                && mEnvironment.deviceHasY2038Issue()) {
+            // This check won't prevent a device's system clock exceeding Integer.MAX_VALUE Unix
+            // seconds through the normal passage of time, but it will stop it jumping above 2038
+            // because of a "bad" suggestion. b/204193177
+            Slog.w(LOG_TAG, "Suggested value is above max time supported by this device."
+                    + " suggestion=" + suggestion);
+            return false;
+        }
         return true;
     }
 
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
index 7e4f0e7..2617f4d 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/DeviceSide/Android.bp
@@ -38,5 +38,4 @@
         "androidx.test.rules",
         "truth-prebuilt",
     ],
-    platform_apis: true,
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index a227cd3..035249e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -70,6 +70,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -516,6 +517,7 @@
         }
     }
 
+    @Ignore("Causing breakages so ignoring to resolve, b/231667368")
     @Test
     public void initRecoveryService_alwaysUpdatesCertsWhenTestRootCertIsUsed() throws Exception {
         int uid = Binder.getCallingUid();
@@ -539,6 +541,7 @@
                 testRootCertAlias)).isEqualTo(TestData.getInsecureCertPathForEndpoint2());
     }
 
+    @Ignore("Causing breakages so ignoring to resolve, b/231667368")
     @Test
     public void initRecoveryService_updatesCertsIndependentlyForDifferentRoots() throws Exception {
         int uid = Binder.getCallingUid();
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 2d9903f..2248ddb 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -1131,6 +1131,49 @@
                 .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
     }
 
+    @Test
+    public void manualY2038SuggestionsAreRejectedOnAffectedDevices() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(false)
+                .pokeAutoOriginPriorities(ORIGIN_TELEPHONY)
+                .pokeDeviceHasY2038Issues(true);
+
+        Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
+        ManualTimeSuggestion timeSuggestion = mScript.generateManualTimeSuggestion(y2038IssueTime);
+        mScript.simulateManualTimeSuggestion(timeSuggestion, false /* expectedResult */)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void telephonyY2038SuggestionsAreRejectedOnAffectedDevices() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true)
+                .pokeAutoOriginPriorities(ORIGIN_TELEPHONY)
+                .pokeDeviceHasY2038Issues(true);
+
+        final int slotIndex = 0;
+        Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
+        TelephonyTimeSuggestion timeSuggestion =
+                mScript.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime);
+        mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasNotSetAndResetCallTracking();
+    }
+
+    @Test
+    public void telephonyY2038SuggestionsAreNotRejectedOnUnaffectedDevices() {
+        mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+                .pokeAutoTimeDetectionEnabled(true)
+                .pokeAutoOriginPriorities(ORIGIN_TELEPHONY)
+                .pokeDeviceHasY2038Issues(false);
+
+        final int slotIndex = 0;
+        Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L);
+        TelephonyTimeSuggestion timeSuggestion =
+                mScript.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime);
+        mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+                .verifySystemClockWasSetAndResetCallTracking(y2038IssueTime.toEpochMilli());
+    }
+
     /**
      * A fake implementation of {@link TimeDetectorStrategyImpl.Environment}. Besides tracking
      * changes and behaving like the real thing should, it also asserts preconditions.
@@ -1143,6 +1186,7 @@
         private int mSystemClockUpdateThresholdMillis = 2000;
         private int[] mAutoOriginPriorities = PROVIDERS_PRIORITY;
         private ConfigurationChangeListener mConfigChangeListener;
+        private boolean mDeviceHas2038Issues = false;
 
         // Tracking operations.
         private boolean mSystemClockWasSet;
@@ -1208,6 +1252,15 @@
             mWakeLockAcquired = false;
         }
 
+        public void setDeviceHas2038Issues(boolean hasIssues) {
+            mDeviceHas2038Issues = hasIssues;
+        }
+
+        @Override
+        public boolean deviceHasY2038Issue() {
+            return mDeviceHas2038Issues;
+        }
+
         // Methods below are for managing the fake's behavior.
 
         void pokeSystemClockUpdateThreshold(int thresholdMillis) {
@@ -1304,6 +1357,11 @@
             return this;
         }
 
+        Script pokeDeviceHasY2038Issues(boolean hasIssues) {
+            mFakeEnvironment.setDeviceHas2038Issues(hasIssues);
+            return this;
+        }
+
         long peekElapsedRealtimeMillis() {
             return mFakeEnvironment.peekElapsedRealtimeMillis();
         }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6122b08..8a8cdb0 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SuppressLint;
@@ -31,6 +32,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -70,6 +72,7 @@
  */
 @SuppressAutoDoc
 @SystemService(Context.TELECOM_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TELECOM)
 public class TelecomManager {
 
     /**
diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
index f47cf33..e7d95e4 100644
--- a/telephony/java/android/telephony/AnomalyReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -16,6 +16,8 @@
 
 package android.telephony;
 
+import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
+
 import static com.android.internal.telephony.TelephonyStatsLog.TELEPHONY_ANOMALY_DETECTED;
 
 import android.annotation.NonNull;
@@ -73,6 +75,7 @@
      *
      * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is
      * system protected. Invoking this method unless you are the system will result in an error.
+     * Carrier Id will be set as UNKNOWN_CARRIER_ID.
      *
      * @param eventId a fixed event ID that will be sent for each instance of the same event. This
      *        ID should be generated randomly.
@@ -81,6 +84,23 @@
      *        static and must not contain any sensitive information (especially PII).
      */
     public static void reportAnomaly(@NonNull UUID eventId, String description) {
+        reportAnomaly(eventId, description, UNKNOWN_CARRIER_ID);
+    }
+
+    /**
+     * If enabled, build and send an intent to a Debug Service for logging.
+     *
+     * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is
+     * system protected. Invoking this method unless you are the system will result in an error.
+     *
+     * @param eventId a fixed event ID that will be sent for each instance of the same event. This
+     *        ID should be generated randomly.
+     * @param description an optional description, that if included will be used as the subject for
+     *        identification and discussion of this event. This description should ideally be
+     *        static and must not contain any sensitive information (especially PII).
+     * @param carrierId the carrier of the id associated with this event.
+     */
+    public static void reportAnomaly(@NonNull UUID eventId, String description, int carrierId) {
         if (sContext == null) {
             Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId);
             return;
@@ -88,7 +108,7 @@
 
         TelephonyStatsLog.write(
                 TELEPHONY_ANOMALY_DETECTED,
-                0, // TODO: carrier id needs to be populated
+                carrierId,
                 eventId.getLeastSignificantBits(),
                 eventId.getMostSignificantBits());
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0d0142c..8956b46 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SuppressLint;
@@ -28,6 +29,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.NetworkCapabilities;
 import android.net.ipsec.ike.SaProposal;
 import android.os.Build;
@@ -55,6 +57,7 @@
  * Provides access to telephony configuration values that are carrier-specific.
  */
 @SystemService(Context.CARRIER_CONFIG_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
 public class CarrierConfigManager {
     private final static String TAG = "CarrierConfigManager";
 
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index fa6de1a..ac1f376 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -1673,4 +1673,9 @@
             return UNKNOWN;
         }
     }
+
+    /** @hide */
+    public static boolean isFailCauseExisting(@DataFailureCause int failCause) {
+        return sFailCauseMap.containsKey(failCause);
+    }
 }
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index 6b9871c..b0ff949 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -17,11 +17,13 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresFeature;
 import android.annotation.SdkConstant;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.telephony.BinderCacheManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -33,6 +35,7 @@
  * Provides access to information about Telephony IMS services on the device.
  */
 @SystemService(Context.TELEPHONY_IMS_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
 public class ImsManager {
 
     /**
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index d91134e..d978f57 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -23,16 +23,12 @@
 import android.os.Parcelable;
 import android.telephony.Annotation.NetworkType;
 
-import com.android.telephony.Rlog;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 import java.util.Objects;
 
 public final class PhysicalChannelConfig implements Parcelable {
-    static final String TAG = "PhysicalChannelConfig";
-
     // TODO(b/72993578) consolidate these enums in a central location.
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -571,21 +567,19 @@
 
         public @NonNull Builder setNetworkType(@NetworkType int networkType) {
             if (!TelephonyManager.isNetworkTypeValid(networkType)) {
-                Rlog.e(TAG, "Builder.setNetworkType: Network type " + networkType + " is invalid.");
-            } else {
-                mNetworkType = networkType;
+                throw new IllegalArgumentException("Network type " + networkType + " is invalid.");
             }
+            mNetworkType = networkType;
             return this;
         }
 
         public @NonNull Builder setFrequencyRange(int frequencyRange) {
             if (!ServiceState.isFrequencyRangeValid(frequencyRange)
                     && frequencyRange != ServiceState.FREQUENCY_RANGE_UNKNOWN) {
-                Rlog.e(TAG, "Builder.setFrequencyRange: Frequency range " + frequencyRange
+                throw new IllegalArgumentException("Frequency range " + frequencyRange
                         + " is invalid.");
-            } else {
-                mFrequencyRange = frequencyRange;
             }
+            mFrequencyRange = frequencyRange;
             return this;
         }
 
@@ -601,21 +595,19 @@
 
         public @NonNull Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) {
             if (cellBandwidthDownlinkKhz < CELL_BANDWIDTH_UNKNOWN) {
-                Rlog.e(TAG, "Builder.setCellBandwidthDownlinkKhz: Cell downlink bandwidth(kHz) "
+                throw new IllegalArgumentException("Cell downlink bandwidth(kHz) "
                         + cellBandwidthDownlinkKhz + " is invalid.");
-            } else {
-                mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
             }
+            mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz;
             return this;
         }
 
         public @NonNull Builder setCellBandwidthUplinkKhz(int cellBandwidthUplinkKhz) {
             if (cellBandwidthUplinkKhz < CELL_BANDWIDTH_UNKNOWN) {
-                Rlog.e(TAG, "Builder.setCellBandwidthUplinkKhz: Cell uplink bandwidth(kHz) "
+                throw new IllegalArgumentException("Cell uplink bandwidth(kHz) "
                         + cellBandwidthUplinkKhz + " is invalid.");
-            } else {
-                mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz;
             }
+            mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz;
             return this;
         }
 
@@ -632,20 +624,18 @@
 
         public @NonNull Builder setPhysicalCellId(int physicalCellId) {
             if (physicalCellId > PHYSICAL_CELL_ID_MAXIMUM_VALUE) {
-                Rlog.e(TAG, "Builder.setPhysicalCellId: Physical cell ID " + physicalCellId
+                throw new IllegalArgumentException("Physical cell ID " + physicalCellId
                         + " is over limit.");
-            } else {
-                mPhysicalCellId = physicalCellId;
             }
+            mPhysicalCellId = physicalCellId;
             return this;
         }
 
         public @NonNull Builder setBand(int band) {
             if (band <= BAND_UNKNOWN) {
-                Rlog.e(TAG, "Builder.setBand: Band " + band + " is invalid.");
-            } else {
-                mBand = band;
+                throw new IllegalArgumentException("Band " + band + " is invalid.");
             }
+            mBand = band;
             return this;
         }
     }
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 5171cf9..7df06b0 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -22,6 +22,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SystemApi;
@@ -32,6 +33,7 @@
 import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.CursorWindow;
 import android.net.Uri;
 import android.os.Build;
@@ -75,6 +77,7 @@
  *
  * @see SubscriptionManager#getActiveSubscriptionInfoList()
  */
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
 public final class SmsManager {
     private static final String TAG = "SmsManager";
 
@@ -2633,6 +2636,19 @@
      *  sending the message.
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @throws IllegalArgumentException if contentUri is empty
      */
     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
@@ -2661,6 +2677,19 @@
      *  sending the message.
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @param messageId an id that uniquely identifies the message requested to be sent.
      * Used for logging and diagnostics purposes. The id may be 0.
      * @throws IllegalArgumentException if contentUri is empty
@@ -2707,6 +2736,19 @@
      *  downloading the message.
      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is downloaded, or the download is failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @throws IllegalArgumentException if locationUrl or contentUri is empty
      */
     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
@@ -2737,6 +2779,19 @@
      *  downloading the message.
      * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is downloaded, or the download is failed
+     * The result code will be <code>Activity.RESULT_OK</code> for success
+     * or one of these errors:<br>
+     * <code>MMS_ERROR_UNSPECIFIED</code><br>
+     * <code>MMS_ERROR_INVALID_APN</code><br>
+     * <code>MMS_ERROR_UNABLE_CONNECT_MMS</code><br>
+     * <code>MMS_ERROR_HTTP_FAILURE</code><br>
+     * <code>MMS_ERROR_IO_ERROR</code><br>
+     * <code>MMS_ERROR_RETRY</code><br>
+     * <code>MMS_ERROR_CONFIGURATION_ERROR</code><br>
+     * <code>MMS_ERROR_NO_DATA_NETWORK</code><br>
+     * <code>MMS_ERROR_INVALID_SUBSCRIPTION_ID</code><br>
+     * <code>MMS_ERROR_INACTIVE_SUBSCRIPTION</code><br>
+     * <code>MMS_ERROR_DATA_DISABLED</code><br>
      * @param messageId an id that uniquely identifies the message requested to be downloaded.
      * Used for logging and diagnostics purposes. The id may be 0.
      * @throws IllegalArgumentException if locationUrl or contentUri is empty
@@ -2768,15 +2823,62 @@
     }
 
     // MMS send/download failure result codes
+
+    /**
+     * Unspecific MMS error occurred during send/download.
+     */
     public static final int MMS_ERROR_UNSPECIFIED = 1;
+
+    /**
+     * ApnException occurred during MMS network setup.
+     */
     public static final int MMS_ERROR_INVALID_APN = 2;
+
+    /**
+     * An error occurred during the MMS connection setup.
+     */
     public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
+
+    /**
+     * An error occurred during the HTTP client setup.
+     */
     public static final int MMS_ERROR_HTTP_FAILURE = 4;
+
+    /**
+     * An I/O error occurred reading the PDU.
+     */
     public static final int MMS_ERROR_IO_ERROR = 5;
+
+    /**
+     * An error occurred while retrying sending/downloading the MMS.
+     */
     public static final int MMS_ERROR_RETRY = 6;
+
+    /**
+     * The carrier-dependent configuration values could not be loaded.
+     */
     public static final int MMS_ERROR_CONFIGURATION_ERROR = 7;
+
+    /**
+     * There is no data network.
+     */
     public static final int MMS_ERROR_NO_DATA_NETWORK = 8;
 
+    /**
+     * The subscription id for the send/download is invalid.
+     */
+    public static final int MMS_ERROR_INVALID_SUBSCRIPTION_ID = 9;
+
+    /**
+     * The subscription id for the send/download is inactive.
+     */
+    public static final int MMS_ERROR_INACTIVE_SUBSCRIPTION = 10;
+
+    /**
+     * Data is disabled for the MMS APN.
+     */
+    public static final int MMS_ERROR_DATA_DISABLED = 11;
+
     /** Intent extra name for MMS sending result data in byte array type */
     public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 974392e..d2858ec 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -26,6 +26,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
@@ -92,6 +93,7 @@
  * and provides information about the current Telephony Subscriptions.
  */
 @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
 public class SubscriptionManager {
     private static final String LOG_TAG = "SubscriptionManager";
     private static final boolean DBG = false;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 87c337d..bbd3c46 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -49,6 +49,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.ConnectivityManager;
 import android.net.Uri;
@@ -174,6 +175,7 @@
  * that do not implement this feature, the behavior is not reliable.
  */
 @SystemService(Context.TELEPHONY_SERVICE)
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY)
 public class TelephonyManager {
     private static final String TAG = "TelephonyManager";
 
@@ -2055,6 +2057,7 @@
      */
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM)
     public String getImei() {
         return getImei(getSlotIndex());
     }
@@ -2096,6 +2099,7 @@
      */
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM)
     public String getImei(int slotIndex) {
         ITelephony telephony = getITelephony();
         if (telephony == null) return null;
@@ -2113,6 +2117,7 @@
      * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not
      * available.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM)
     @Nullable
     public String getTypeAllocationCode() {
         return getTypeAllocationCode(getSlotIndex());
@@ -2124,6 +2129,7 @@
      *
      * @param slotIndex of which Type Allocation Code is returned
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM)
     @Nullable
     public String getTypeAllocationCode(int slotIndex) {
         ITelephony telephony = getITelephony();
@@ -2170,6 +2176,7 @@
      */
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public String getMeid() {
         return getMeid(getSlotIndex());
     }
@@ -2208,6 +2215,7 @@
      */
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public String getMeid(int slotIndex) {
         ITelephony telephony = getITelephony();
         if (telephony == null) return null;
@@ -2231,6 +2239,7 @@
      * Returns the Manufacturer Code from the MEID. Return null if Manufacturer Code is not
      * available.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     @Nullable
     public String getManufacturerCode() {
         return getManufacturerCode(getSlotIndex());
@@ -2242,6 +2251,7 @@
      *
      * @param slotIndex of which Type Allocation Code is returned
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     @Nullable
     public String getManufacturerCode(int slotIndex) {
         ITelephony telephony = getITelephony();
@@ -2287,6 +2297,7 @@
      */
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getNai() {
         return getNaiBySubscriberId(getSubId());
     }
@@ -2620,6 +2631,7 @@
      * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
      * on a CDMA network).
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public String getNetworkOperatorName() {
         return getNetworkOperatorName(getSubId());
     }
@@ -2647,6 +2659,7 @@
      * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if
      * on a CDMA network).
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public String getNetworkOperator() {
         return getNetworkOperatorForPhone(getPhoneId());
     }
@@ -2695,6 +2708,7 @@
      * @see #createForSubscriptionId(int)
      * @see #createForPhoneAccountHandle(PhoneAccountHandle)
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public String getNetworkSpecifier() {
         return String.valueOf(getSubId());
     }
@@ -2717,6 +2731,7 @@
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @WorkerThread
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public PersistableBundle getCarrierConfig() {
         CarrierConfigManager carrierConfigManager = mContext
                 .getSystemService(CarrierConfigManager.class);
@@ -2729,6 +2744,7 @@
      * <p>
      * Availability: Only when user registered to a network.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean isNetworkRoaming() {
         return isNetworkRoaming(getSubId());
     }
@@ -2758,6 +2774,7 @@
      * @return the lowercase 2 character ISO-3166-1 alpha-2 country code, or empty string if not
      * available.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public String getNetworkCountryIso() {
         return getNetworkCountryIso(getSlotIndex());
     }
@@ -2780,6 +2797,7 @@
      * @throws IllegalArgumentException when the slotIndex is invalid.
      *
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     @NonNull
     public String getNetworkCountryIso(int slotIndex) {
         try {
@@ -2997,6 +3015,7 @@
     @RequiresPermission(anyOf = {
             android.Manifest.permission.READ_PHONE_STATE,
             android.Manifest.permission.READ_BASIC_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public @NetworkType int getDataNetworkType() {
         return getDataNetworkType(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
     }
@@ -3042,6 +3061,7 @@
     @RequiresPermission(anyOf = {
             android.Manifest.permission.READ_PHONE_STATE,
             android.Manifest.permission.READ_BASIC_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public @NetworkType int getVoiceNetworkType() {
         return getVoiceNetworkType(getSubId());
     }
@@ -3381,6 +3401,7 @@
     /**
      * @return true if a ICC card is present
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean hasIccCard() {
         return hasIccCard(getSlotIndex());
     }
@@ -3423,6 +3444,7 @@
      * @see #SIM_STATE_CARD_IO_ERROR
      * @see #SIM_STATE_CARD_RESTRICTED
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @SimState int getSimState() {
         int simState = getSimStateIncludingLoaded();
         if (simState == SIM_STATE_LOADED) {
@@ -3465,6 +3487,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @SimState int getSimCardState() {
         int simState = getSimState();
         return getSimCardStateFromSimState(simState);
@@ -3510,6 +3533,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @SimState int getSimCardState(int physicalSlotIndex, int portIndex) {
         int simState = getSimState(getLogicalSlotIndex(physicalSlotIndex, portIndex));
         return getSimCardStateFromSimState(simState);
@@ -3566,6 +3590,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @SimState int getSimApplicationState() {
         int simState = getSimStateIncludingLoaded();
         return getSimApplicationStateFromSimState(simState);
@@ -3618,6 +3643,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @SimState int getSimApplicationState(int physicalSlotIndex, int portIndex) {
         int simState =
                 SubscriptionManager.getSimStateForSlotIndex(getLogicalSlotIndex(physicalSlotIndex,
@@ -3659,6 +3685,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean isApplicationOnUicc(@UiccAppType int appType) {
         try {
             ITelephony service = getITelephony();
@@ -3687,6 +3714,7 @@
      * @see #SIM_STATE_CARD_IO_ERROR
      * @see #SIM_STATE_CARD_RESTRICTED
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @SimState int getSimState(int slotIndex) {
         int simState = SubscriptionManager.getSimStateForSlotIndex(slotIndex);
         if (simState == SIM_STATE_LOADED) {
@@ -3703,6 +3731,7 @@
      *
      * @see #getSimState
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getSimOperator() {
         return getSimOperatorNumeric();
     }
@@ -3787,6 +3816,7 @@
      *
      * @see #getSimState
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getSimOperatorName() {
         return getSimOperatorNameForPhone(getPhoneId());
     }
@@ -3824,6 +3854,7 @@
      * @return the lowercase 2 character ISO-3166-1 alpha-2 country code, or empty string is not
      * available.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getSimCountryIso() {
         return getSimCountryIsoForPhone(getPhoneId());
     }
@@ -3882,6 +3913,7 @@
      */
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getSimSerialNumber() {
          return getSimSerialNumber(getSubId());
     }
@@ -3949,6 +3981,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean isLteCdmaEvdoGsmWcdmaEnabled() {
         return getLteOnCdmaMode(getSubId()) == PhoneConstants.LTE_ON_CDMA_TRUE;
     }
@@ -3992,6 +4025,7 @@
      *
      * @return card ID of the default eUICC card, if loaded.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC)
     public int getCardIdForDefaultEuicc() {
         try {
             ITelephony telephony = getITelephony();
@@ -4025,6 +4059,7 @@
      * the caller does not have adequate permissions for that card.
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @NonNull
     public List<UiccCardInfo> getUiccCardsInfo() {
         try {
@@ -4050,6 +4085,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public UiccSlotInfo[] getUiccSlotsInfo() {
         try {
             ITelephony telephony = getITelephony();
@@ -4192,6 +4228,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public void setSimSlotMapping(@NonNull Collection<UiccSlotMapping> slotMapping) {
         try {
             ITelephony telephony = getITelephony();
@@ -4255,6 +4292,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @NonNull
     public Collection<UiccSlotMapping> getSimSlotMapping() {
         List<UiccSlotMapping> slotMap = new ArrayList<>();
@@ -4310,6 +4348,7 @@
      */
     @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getSubscriberId() {
         return getSubscriberId(getSubId());
     }
@@ -4361,6 +4400,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @SystemApi
     @Nullable
     public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(@KeyType int keyType) {
@@ -4405,6 +4445,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @SystemApi
     public void resetCarrierKeysForImsiEncryption() {
         try {
@@ -4604,6 +4645,7 @@
      * @param callback A callback called when the upload operation terminates, either in success
      *                 or in error.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void uploadCallComposerPicture(@NonNull Path pictureToUpload,
             @NonNull String contentType,
             @CallbackExecutor @NonNull Executor executor,
@@ -4710,6 +4752,7 @@
      * @param callback A callback called when the upload operation terminates, either in success
      *                 or in error.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void uploadCallComposerPicture(@NonNull InputStream pictureToUpload,
             @NonNull String contentType,
             @CallbackExecutor @NonNull Executor executor,
@@ -4845,6 +4888,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getGroupIdLevel1() {
         try {
             IPhoneSubInfo info = getSubscriberInfoService();
@@ -5100,6 +5144,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @NonNull String[] getMergedImsisFromGroup() {
         try {
             ITelephony telephony = getITelephony();
@@ -5179,6 +5224,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public String getVoiceMailNumber() {
         return getVoiceMailNumber(getSubId());
     }
@@ -5214,6 +5260,7 @@
      * @param alphaTag The alpha tag to display.
      * @param number The voicemail number.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean setVoiceMailNumber(String alphaTag, String number) {
         return setVoiceMailNumber(getSubId(), alphaTag, number);
     }
@@ -5253,6 +5300,7 @@
      * be implemented instead.
      */
     @SystemApi
+    @Deprecated
     @SuppressLint("RequiresPermission")
     public void setVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle, boolean enabled){
     }
@@ -5267,6 +5315,7 @@
      * be implemented instead.
      */
     @SystemApi
+    @Deprecated
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     @SuppressLint("RequiresPermission")
     public boolean isVisualVoicemailEnabled(PhoneAccountHandle phoneAccountHandle){
@@ -5288,6 +5337,7 @@
      */
     @SystemApi
     @SuppressLint("RequiresPermission")
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     @Nullable
     public Bundle getVisualVoicemailSettings(){
         try {
@@ -5317,6 +5367,7 @@
     @Nullable
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public String getVisualVoicemailPackageName() {
         try {
             ITelephony telephony = getITelephony();
@@ -5343,6 +5394,7 @@
      * @see TelecomManager#getDefaultDialerPackage()
      * @see CarrierConfigManager#KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings settings) {
         if (settings == null) {
             disableVisualVoicemailSmsFilter(mSubId);
@@ -5372,6 +5424,7 @@
      * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent)
      * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent)
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void sendVisualVoicemailSms(String number, int port, String text,
             PendingIntent sentIntent) {
         sendVisualVoicemailSmsForSubscriber(mSubId, number, port, text, sentIntent);
@@ -5559,6 +5612,7 @@
       */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void setVoiceActivationState(@SimActivationState int activationState) {
         setVoiceActivationState(getSubId(), activationState);
     }
@@ -5606,6 +5660,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public void setDataActivationState(@SimActivationState int activationState) {
         setDataActivationState(getSubId(), activationState);
     }
@@ -5653,6 +5708,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public @SimActivationState int getVoiceActivationState() {
         return getVoiceActivationState(getSubId());
     }
@@ -5702,6 +5758,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public @SimActivationState int getDataActivationState() {
         return getDataActivationState(getSubId());
     }
@@ -5778,6 +5835,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public String getVoiceMailAlphaTag() {
         return getVoiceMailAlphaTag(getSubId());
     }
@@ -5860,6 +5918,7 @@
     @Nullable
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getIsimDomain() {
         try {
             IPhoneSubInfo info = getSubscriberInfoService();
@@ -5960,6 +6019,7 @@
      * @return The call state of the subscription associated with this TelephonyManager instance.
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public @CallState int getCallStateForSubscription() {
         return getCallState(getSubId());
     }
@@ -6058,6 +6118,7 @@
      * @see #DATA_ACTIVITY_INOUT
      * @see #DATA_ACTIVITY_DORMANT
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public int getDataActivity() {
         try {
             ITelephony telephony = getITelephony();
@@ -6130,6 +6191,7 @@
      * @see #DATA_DISCONNECTING
      * @see #DATA_HANDOVER_IN_PROGRESS
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public int getDataState() {
         try {
             ITelephony telephony = getITelephony();
@@ -6406,6 +6468,7 @@
      * on any device with a telephony radio, even if the device is
      * data-only.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean isVoiceCapable() {
         if (mContext == null) return true;
         return mContext.getResources().getBoolean(
@@ -6421,6 +6484,7 @@
      * Note: Voicemail waiting sms, cell broadcasting sms, and MMS are
      *       disabled when device doesn't support sms.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public boolean isSmsCapable() {
         if (mContext == null) return true;
         return mContext.getResources().getBoolean(
@@ -6470,6 +6534,7 @@
      * information is unavailable.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public List<CellInfo> getAllCellInfo() {
         try {
             ITelephony telephony = getITelephony();
@@ -6564,6 +6629,7 @@
      * @param callback a callback to receive CellInfo.
      */
     @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void requestCellInfoUpdate(
             @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
         try {
@@ -6627,6 +6693,7 @@
     @SystemApi
     @RequiresPermission(allOf = {android.Manifest.permission.ACCESS_FINE_LOCATION,
             android.Manifest.permission.MODIFY_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void requestCellInfoUpdate(@NonNull WorkSource workSource,
             @NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
         try {
@@ -6708,6 +6775,7 @@
     /**
      * Returns the MMS user agent.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public String getMmsUserAgent() {
         try {
             ITelephony telephony = getITelephony();
@@ -6723,6 +6791,7 @@
     /**
      * Returns the MMS user agent profile URL.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public String getMmsUAProfUrl() {
         try {
             ITelephony telephony = getITelephony();
@@ -6784,6 +6853,7 @@
      * @deprecated instead use {@link #iccOpenLogicalChannelByPort(int, int, String, int)}
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @SystemApi
     @Nullable
     @Deprecated
@@ -6883,6 +6953,7 @@
      * @param p2 P2 parameter (described in ISO 7816-4).
      * @return an IccOpenLogicalChannelResponse object.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) {
         return iccOpenLogicalChannel(getSubId(), AID, p2);
     }
@@ -6951,6 +7022,7 @@
      * @deprecated instead use {@link #iccCloseLogicalChannelByPort(int, int, int)}
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @SystemApi
     @Deprecated
     public boolean iccCloseLogicalChannelBySlot(int slotIndex, int channel) {
@@ -7020,6 +7092,7 @@
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean iccCloseLogicalChannel(int channel) {
         return iccCloseLogicalChannel(getSubId(), channel);
     }
@@ -7082,6 +7155,7 @@
      * {@link #iccTransmitApduLogicalChannelByPort(int, int, int, int, int, int, int, int, String)}
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @SystemApi
     @Nullable
     @Deprecated
@@ -7164,6 +7238,7 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
         return iccTransmitApduLogicalChannel(getSubId(), channel, cla,
@@ -7232,6 +7307,7 @@
      * {@link #iccTransmitApduBasicChannelByPort(int, int, int, int, int, int, int, String)}
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @SystemApi
     @NonNull
     @Deprecated
@@ -7309,6 +7385,7 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String iccTransmitApduBasicChannel(int cla,
             int instruction, int p1, int p2, int p3, String data) {
         return iccTransmitApduBasicChannel(getSubId(), cla,
@@ -7364,6 +7441,7 @@
      * @param filePath
      * @return The APDU response.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
             String filePath) {
         return iccExchangeSimIO(getSubId(), fileID, command, p1, p2, p3, filePath);
@@ -7412,6 +7490,7 @@
      *         with the last 4 bytes being the status word. If the command fails,
      *         returns an empty string.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String sendEnvelopeWithStatus(String content) {
         return sendEnvelopeWithStatus(getSubId(), content);
     }
@@ -7575,6 +7654,7 @@
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean resetRadioConfig() {
         try {
             ITelephony telephony = getITelephony();
@@ -7602,6 +7682,7 @@
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean rebootRadio() {
         try {
             ITelephony telephony = getITelephony();
@@ -7623,6 +7704,7 @@
      * subscription ID is returned. Otherwise, the default subscription ID will be returned.
      *
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int getSubscriptionId() {
         return getSubId();
     }
@@ -7733,6 +7815,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void requestNumberVerification(@NonNull PhoneNumberRange range, long timeoutMillis,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull NumberVerificationCallback callback) {
@@ -7946,6 +8029,7 @@
     @Nullable
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getIsimIst() {
         try {
             IPhoneSubInfo info = getSubscriberInfoService();
@@ -8030,6 +8114,7 @@
     // TODO(b/73660190): This should probably require MODIFY_PHONE_STATE, not
     // READ_PRIVILEGED_PHONE_STATE. It certainly shouldn't reference the permission in Javadoc since
     // it's not public API.
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getIccAuthentication(int appType, int authType, String data) {
         return getIccAuthentication(getSubId(), appType, authType, data);
     }
@@ -8083,6 +8168,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String[] getForbiddenPlmns() {
       return getForbiddenPlmns(getSubId(), APPTYPE_USIM);
     }
@@ -8132,6 +8218,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int setForbiddenPlmns(@NonNull List<String> fplmns) {
         try {
             ITelephony telephony = getITelephony();
@@ -8158,6 +8245,7 @@
     @SystemApi
     @WorkerThread
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
     public void resetIms(int slotIndex) {
         try {
             ITelephony telephony = getITelephony();
@@ -8592,6 +8680,7 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @NetworkTypeBitMask long getAllowedNetworkTypesBitmask() {
         try {
             ITelephony telephony = getITelephony();
@@ -8643,6 +8732,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void setNetworkSelectionModeAutomatic() {
         try {
             ITelephony telephony = getITelephony();
@@ -8731,6 +8821,7 @@
             android.Manifest.permission.MODIFY_PHONE_STATE,
             Manifest.permission.ACCESS_FINE_LOCATION
     })
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public NetworkScan requestNetworkScan(
             NetworkScanRequest request, Executor executor,
             TelephonyScanManager.NetworkScanCallback callback) {
@@ -8823,6 +8914,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean setNetworkSelectionModeManual(String operatorNumeric, boolean persistSelection) {
         return setNetworkSelectionModeManual(
                 new OperatorInfo(
@@ -8852,6 +8944,7 @@
      * @return {@code true} on success; {@code false} on any failure.
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean setNetworkSelectionModeManual(@NonNull String operatorNumeric,
             boolean persistSelection, @AccessNetworkConstants.RadioAccessNetworkType int ran) {
         return setNetworkSelectionModeManual(new OperatorInfo("" /* operatorAlphaLong */,
@@ -8907,6 +9000,7 @@
             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
             android.Manifest.permission.READ_PRECISE_PHONE_STATE
     })
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @NetworkSelectionMode int getNetworkSelectionMode() {
         int mode = NETWORK_SELECTION_MODE_UNKNOWN;
         try {
@@ -8932,6 +9026,7 @@
      */
     @SuppressAutoDoc // No support carrier privileges (b/72967236).
     @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @NonNull String getManualNetworkSelectionPlmn() {
         try {
             ITelephony telephony = getITelephony();
@@ -8961,6 +9056,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public boolean isInEmergencySmsMode() {
         try {
             ITelephony telephony = getITelephony();
@@ -9271,6 +9367,7 @@
      *
      * @return true on success; false on any failure.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean setPreferredNetworkTypeToGlobal() {
         return setPreferredNetworkTypeToGlobal(getSubId());
     }
@@ -9298,6 +9395,7 @@
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isTetheringApnRequired() {
         return isTetheringApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
     }
@@ -9347,6 +9445,7 @@
      *
      * @return true if the app has carrier privileges.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean hasCarrierPrivileges() {
         return hasCarrierPrivileges(getSubId());
     }
@@ -9393,6 +9492,7 @@
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean setOperatorBrandOverride(String brand) {
         return setOperatorBrandOverride(getSubId(), brand);
     }
@@ -9495,6 +9595,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public String getCdmaMdn() {
         return getCdmaMdn(getSubId());
     }
@@ -9502,6 +9603,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public String getCdmaMdn(int subId) {
         try {
             ITelephony telephony = getITelephony();
@@ -9518,6 +9620,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public String getCdmaMin() {
         return getCdmaMin(getSubId());
     }
@@ -9525,6 +9628,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public String getCdmaMin(int subId) {
         try {
             ITelephony telephony = getITelephony();
@@ -9541,6 +9645,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int checkCarrierPrivilegesForPackage(String pkgName) {
         try {
             ITelephony telephony = getITelephony();
@@ -9557,6 +9662,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int checkCarrierPrivilegesForPackageAnyPhone(String pkgName) {
         try {
             ITelephony telephony = getITelephony();
@@ -9572,6 +9678,7 @@
 
     /** @hide */
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public List<String> getCarrierPackageNamesForIntent(Intent intent) {
         return getCarrierPackageNamesForIntentAndPhone(intent, getPhoneId());
     }
@@ -9579,6 +9686,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public List<String> getCarrierPackageNamesForIntentAndPhone(Intent intent, int phoneId) {
         try {
             ITelephony telephony = getITelephony();
@@ -9660,6 +9768,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @NonNull
     public List<String> getCarrierPrivilegedPackagesForAllActiveSubscriptions() {
         try {
@@ -9706,6 +9815,7 @@
      * @throws SecurityException if the caller does not have the permission.
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void setCallComposerStatus(@CallComposerStatus int status) {
         if (status > CALL_COMPOSER_STATUS_ON
                 || status < CALL_COMPOSER_STATUS_OFF) {
@@ -9734,6 +9844,7 @@
      * {@link #CALL_COMPOSER_STATUS_ON} or {@link #CALL_COMPOSER_STATUS_OFF}.
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public @CallComposerStatus int getCallComposerStatus() {
         try {
             ITelephony telephony = getITelephony();
@@ -9750,6 +9861,7 @@
     /** @hide */
     @SystemApi
     @SuppressLint("RequiresPermission")
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void dial(String number) {
         try {
             ITelephony telephony = getITelephony();
@@ -9882,6 +9994,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean supplyPin(String pin) {
         try {
             ITelephony telephony = getITelephony();
@@ -9896,6 +10009,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean supplyPuk(String puk, String pin) {
         try {
             ITelephony telephony = getITelephony();
@@ -9961,6 +10075,7 @@
     @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public PinResult supplyIccLockPin(@NonNull String pin) {
         try {
             ITelephony telephony = getITelephony();
@@ -9996,6 +10111,7 @@
     @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public PinResult supplyIccLockPuk(@NonNull String puk, @NonNull String pin) {
         try {
             ITelephony telephony = getITelephony();
@@ -10065,6 +10181,7 @@
      * @param handler the {@link Handler} to run the request on.
      */
     @RequiresPermission(android.Manifest.permission.CALL_PHONE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void sendUssdRequest(String ussdRequest,
                                 final UssdResponseCallback callback, Handler handler) {
         checkNotNull(callback, "UssdResponseCallback cannot be null.");
@@ -10107,6 +10224,7 @@
      *
      * @return {@code true} if simultaneous voice and data supported, and {@code false} otherwise.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isConcurrentVoiceAndDataSupported() {
         try {
             ITelephony telephony = getITelephony();
@@ -10149,6 +10267,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void toggleRadioOnOff() {
         try {
             ITelephony telephony = getITelephony();
@@ -10162,6 +10281,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean setRadio(boolean turnOn) {
         try {
             ITelephony telephony = getITelephony();
@@ -10176,6 +10296,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean setRadioPower(boolean turnOn) {
         try {
             ITelephony telephony = getITelephony();
@@ -10197,6 +10318,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void shutdownAllRadios() {
         try {
             ITelephony telephony = getITelephony();
@@ -10217,6 +10339,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean isAnyRadioPoweredOn() {
         try {
             ITelephony telephony = getITelephony();
@@ -10263,6 +10386,7 @@
     @SystemApi
     @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
             android.Manifest.permission.READ_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @RadioPowerState int getRadioPowerState() {
         try {
             ITelephony telephony = getITelephony();
@@ -10289,6 +10413,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean enableDataConnectivity() {
         try {
             ITelephony telephony = getITelephony();
@@ -10303,6 +10428,7 @@
     /** @hide */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean disableDataConnectivity() {
         try {
             ITelephony telephony = getITelephony();
@@ -10316,6 +10442,7 @@
 
     /** @hide */
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isDataConnectivityPossible() {
         try {
             ITelephony telephony = getITelephony();
@@ -10330,6 +10457,7 @@
 
     /** @hide */
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean needsOtaServiceProvisioning() {
         try {
             ITelephony telephony = getITelephony();
@@ -10437,6 +10565,7 @@
             android.Manifest.permission.MODIFY_PHONE_STATE,
             android.Manifest.permission.READ_PHONE_STATE,
             android.Manifest.permission.READ_BASIC_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isDataEnabled() {
         try {
             return isDataEnabledForReason(DATA_ENABLED_REASON_USER);
@@ -10466,6 +10595,7 @@
     @RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE,
             android.Manifest.permission.READ_PHONE_STATE,
             android.Manifest.permission.READ_BASIC_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isDataRoamingEnabled() {
         boolean isDataRoamingEnabled = false;
         try {
@@ -10503,6 +10633,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public @CdmaRoamingMode int getCdmaRoamingMode() {
         int mode = CDMA_ROAMING_MODE_RADIO_DEFAULT;
         try {
@@ -10544,6 +10675,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public void setCdmaRoamingMode(@CdmaRoamingMode int mode) {
         if (getPhoneType() != PHONE_TYPE_CDMA) {
             throw new IllegalStateException("Phone does not support CDMA.");
@@ -10611,6 +10743,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public @CdmaSubscription int getCdmaSubscriptionMode() {
         int mode = CDMA_SUBSCRIPTION_RUIM_SIM;
         try {
@@ -10648,6 +10781,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public void setCdmaSubscriptionMode(@CdmaSubscription int mode) {
         if (getPhoneType() != PHONE_TYPE_CDMA) {
             throw new IllegalStateException("Phone does not support CDMA.");
@@ -10682,6 +10816,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public void setDataRoamingEnabled(boolean isEnabled) {
         try {
             ITelephony telephony = getITelephony();
@@ -10779,6 +10914,7 @@
      *
      * @return {@code true} if the DTMF tone length can be changed, and {@code false} otherwise.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean canChangeDtmfToneLength() {
         try {
             ITelephony telephony = getITelephony();
@@ -10842,6 +10978,7 @@
      *
      * @return {@code true} if the device and carrier both support RTT, {@code false} otherwise.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
     public boolean isRttSupported() {
         try {
             ITelephony telephony = getITelephony();
@@ -10861,6 +10998,7 @@
      * @return {@code true} if the device supports hearing aid compatibility, and {@code false}
      * otherwise.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean isHearingAidCompatibilitySupported() {
         try {
             ITelephony telephony = getITelephony();
@@ -11208,6 +11346,7 @@
      **/
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public void setSimPowerState(@SimPowerState int state, @NonNull Executor executor,
             @NonNull @SetSimPowerStateResult Consumer<Integer> callback) {
         setSimPowerStateForSlot(getSlotIndex(), state, executor, callback);
@@ -11237,6 +11376,7 @@
      **/
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public void setSimPowerStateForSlot(int slotIndex, @SimPowerState int state,
             @NonNull Executor executor,
             @NonNull @SetSimPowerStateResult Consumer<Integer> callback) {
@@ -11451,6 +11591,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public @Nullable ComponentName getAndUpdateDefaultRespondViaMessageApplication() {
         return SmsApplication.getDefaultRespondViaMessageApplication(mContext, true);
     }
@@ -11463,6 +11604,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public @Nullable ComponentName getDefaultRespondViaMessageApplication() {
         return SmsApplication.getDefaultRespondViaMessageApplication(mContext, false);
     }
@@ -11658,6 +11800,7 @@
      *         permission.
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int getSubscriptionId(@NonNull PhoneAccountHandle phoneAccountHandle) {
         int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         try {
@@ -11724,6 +11867,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @Nullable public Locale getSimLocale() {
         try {
             final ITelephony telephony = getITelephony();
@@ -11922,6 +12066,7 @@
             Manifest.permission.READ_PHONE_STATE,
             Manifest.permission.ACCESS_COARSE_LOCATION
     })
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @Nullable ServiceState getServiceState() {
         return getServiceState(false, false);
     }
@@ -12012,6 +12157,7 @@
      * @return The URI for the ringtone to play when receiving a voicemail from a specific
      * PhoneAccount. May be {@code null} if no ringtone is set.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public @Nullable Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) {
         try {
             ITelephony service = getITelephony();
@@ -12039,6 +12185,7 @@
      * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
      * instead.
      */
+    @Deprecated
     public void setVoicemailRingtoneUri(PhoneAccountHandle phoneAccountHandle, Uri uri) {
         try {
             ITelephony service = getITelephony();
@@ -12057,6 +12204,7 @@
      * voicemail vibration setting.
      * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean isVoicemailVibrationEnabled(PhoneAccountHandle accountHandle) {
         try {
             ITelephony service = getITelephony();
@@ -12084,6 +12232,7 @@
      * @deprecated Use {@link android.provider.Settings#ACTION_CHANNEL_NOTIFICATION_SETTINGS}
      * instead.
      */
+    @Deprecated
     public void setVoicemailVibrationEnabled(PhoneAccountHandle phoneAccountHandle,
             boolean enabled) {
         try {
@@ -12110,6 +12259,7 @@
      * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the
      * subscription is unavailable or the carrier cannot be identified.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int getSimCarrierId() {
         try {
             ITelephony service = getITelephony();
@@ -12134,6 +12284,7 @@
      * @return Carrier name of the current subscription. Return {@code null} if the subscription is
      * unavailable or the carrier cannot be identified.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @Nullable CharSequence getSimCarrierIdName() {
         try {
             ITelephony service = getITelephony();
@@ -12171,6 +12322,7 @@
      * Return {@link #UNKNOWN_CARRIER_ID} if the subscription is unavailable or the carrier cannot
      * be identified.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int getSimSpecificCarrierId() {
         try {
             ITelephony service = getITelephony();
@@ -12196,6 +12348,7 @@
      * @return user-facing name of the subscription specific carrier id. Return {@code null} if the
      * subscription is unavailable or the carrier cannot be identified.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @Nullable CharSequence getSimSpecificCarrierIdName() {
         try {
             ITelephony service = getITelephony();
@@ -12223,6 +12376,7 @@
      * @return matching carrier id from sim MCCMNC. Return {@link #UNKNOWN_CARRIER_ID} if the
      * subscription is unavailable or the carrier cannot be identified.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public int getCarrierIdFromSimMccMnc() {
         try {
             ITelephony service = getITelephony();
@@ -12301,6 +12455,7 @@
     @Nullable
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public String getAidForAppType(@UiccAppType int appType) {
         return getAidForAppType(getSubId(), appType);
     }
@@ -12363,6 +12518,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CDMA)
     public String getCdmaPrlVersion() {
         return getCdmaPrlVersion(getSubId());
     }
@@ -12428,6 +12584,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK)
     public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) {
         if (carriers == null || !SubscriptionManager.isValidPhoneId(slotIndex)) {
             return -1;
@@ -12554,6 +12711,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     @SetCarrierRestrictionResult
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK)
     public int setCarrierRestrictionRules(@NonNull CarrierRestrictionRules rules) {
         try {
             ITelephony service = getITelephony();
@@ -12611,6 +12769,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK)
     @Nullable
     public CarrierRestrictionRules getCarrierRestrictionRules() {
         try {
@@ -12670,6 +12829,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void setRadioEnabled(boolean enabled) {
         try {
             ITelephony service = getITelephony();
@@ -12791,6 +12951,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void reportDefaultNetworkStatus(boolean report) {
         try {
             ITelephony service = getITelephony();
@@ -12816,6 +12977,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public void resetAllCarrierActions() {
         try {
             ITelephony service = getITelephony();
@@ -12935,6 +13097,7 @@
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public void setDataEnabledForReason(@DataEnabledReason int reason, boolean enabled) {
         setDataEnabledForReason(getSubId(), reason, enabled);
     }
@@ -12981,6 +13144,7 @@
             android.Manifest.permission.MODIFY_PHONE_STATE,
             android.Manifest.permission.READ_BASIC_PHONE_STATE
     })
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isDataEnabledForReason(@DataEnabledReason int reason) {
         return isDataEnabledForReason(getSubId(), reason);
     }
@@ -13034,6 +13198,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean getEmergencyCallbackMode() {
         return getEmergencyCallbackMode(getSubId());
     }
@@ -13072,6 +13237,7 @@
     @SuppressAutoDoc // No support carrier privileges (b/72967236).
     @RequiresPermission(anyOf = {android.Manifest.permission.READ_PRECISE_PHONE_STATE,
             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean isManualNetworkSelectionAllowed() {
         try {
             ITelephony telephony = getITelephony();
@@ -13092,6 +13258,7 @@
      * @return the most recent cached signal strength info from the modem
      */
     @Nullable
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public SignalStrength getSignalStrength() {
         try {
             ITelephony service = getITelephony();
@@ -13120,6 +13287,7 @@
             android.Manifest.permission.READ_PHONE_STATE,
             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
             android.Manifest.permission.READ_BASIC_PHONE_STATE})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isDataConnectionAllowed() {
         boolean retVal = false;
         try {
@@ -13140,6 +13308,7 @@
      * data connections over the telephony network.
      * <p>
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isDataCapable() {
         if (mContext == null) return true;
         return mContext.getResources().getBoolean(
@@ -13287,6 +13456,7 @@
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean setOpportunisticNetworkState(boolean enable) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean ret = false;
@@ -13315,6 +13485,7 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean isOpportunisticNetworkEnabled() {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         boolean isEnabled = false;
@@ -13506,6 +13677,7 @@
      * @throws SecurityException if the caller does not have the required permission
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @NetworkTypeBitMask long getSupportedRadioAccessFamily() {
         try {
             ITelephony telephony = getITelephony();
@@ -13541,6 +13713,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     @SystemApi
     public void notifyOtaEmergencyNumberDbInstalled() {
         try {
@@ -13567,6 +13740,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     @SystemApi
     public void updateOtaEmergencyNumberDbFilePath(
             @NonNull ParcelFileDescriptor otaParcelFileDescriptor) {
@@ -13592,6 +13766,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     @SystemApi
     public void resetOtaEmergencyNumberDbFilePath() {
         try {
@@ -13651,6 +13826,7 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     @NonNull
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList() {
         Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>();
         try {
@@ -13706,6 +13882,7 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     @NonNull
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
             @EmergencyServiceCategories int categories) {
         Map<Integer, List<EmergencyNumber>> emergencyNumberListForCategories = new HashMap<>();
@@ -13771,6 +13948,7 @@
      * SIM card(s), Android database, modem, network or defaults; {@code false} otherwise.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean isEmergencyNumber(@NonNull String number) {
         try {
             ITelephony telephony = getITelephony();
@@ -13810,6 +13988,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public boolean isPotentialEmergencyNumber(@NonNull String number) {
         try {
             ITelephony telephony = getITelephony();
@@ -13835,6 +14014,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public int getEmergencyNumberDbVersion() {
         try {
             ITelephony telephony = getITelephony();
@@ -13975,6 +14155,7 @@
      *                 See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
      *                 for more details. Pass null if don't care about the result.
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public void setPreferredOpportunisticDataSubscription(int subId, boolean needValidation,
             @Nullable @CallbackExecutor Executor executor, @Nullable Consumer<Integer> callback) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
@@ -14038,6 +14219,7 @@
             android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
             android.Manifest.permission.READ_PHONE_STATE
     })
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public int getPreferredOpportunisticDataSubscription() {
         String packageName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         String attributionTag = mContext != null ? mContext.getAttributionTag() : null;
@@ -14073,6 +14255,7 @@
      *
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void updateAvailableNetworks(@NonNull List<AvailableNetworkInfo> availableNetworks,
             @Nullable @CallbackExecutor Executor executor,
             @UpdateAvailableNetworksResult @Nullable Consumer<Integer> callback) {
@@ -14223,6 +14406,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CARRIERLOCK)
     public void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted) {
         try {
             ITelephony service = getITelephony();
@@ -14276,6 +14460,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @IsMultiSimSupportedResult
     public int isMultiSimSupported() {
         if (getSupportedModemCount() < 2) {
@@ -14306,6 +14491,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public void switchMultiSimConfig(int numOfSims) {
         try {
             ITelephony telephony = getITelephony();
@@ -14331,6 +14517,7 @@
      * configurations, otherwise return {@code false}.
      */
     @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean doesSwitchMultiSimConfigTriggerReboot() {
         try {
             ITelephony service = getITelephony();
@@ -14383,6 +14570,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @CarrierPrivilegeStatus int getCarrierPrivilegeStatus(int uid) {
         try {
             ITelephony telephony = getITelephony();
@@ -14496,6 +14684,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isDataEnabledForApn(@ApnType int apnType) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         try {
@@ -14517,6 +14706,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isApnMetered(@ApnType int apnType) {
         try {
             ITelephony service = getITelephony();
@@ -14545,6 +14735,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void setSystemSelectionChannels(@NonNull List<RadioAccessSpecifier> specifiers,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull Consumer<Boolean> callback) {
@@ -14562,6 +14753,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void setSystemSelectionChannels(@NonNull List<RadioAccessSpecifier> specifiers) {
         Objects.requireNonNull(specifiers, "Specifiers must not be null.");
         setSystemSelectionChannelsInternal(specifiers, null, null);
@@ -14608,6 +14800,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public @NonNull List<RadioAccessSpecifier> getSystemSelectionChannels() {
         try {
             ITelephony service = getITelephony();
@@ -14635,6 +14828,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public boolean matchesCurrentSimOperator(@NonNull String mccmnc, @MvnoType int mvnoType,
             @Nullable String mvnoMatchData) {
         try {
@@ -14725,6 +14919,7 @@
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void getCallForwarding(@CallForwardingReason int callForwardingReason,
             @NonNull Executor executor, @NonNull CallForwardingInfoCallback callback) {
         if (callForwardingReason < CallForwardingInfo.REASON_UNCONDITIONAL
@@ -14800,6 +14995,7 @@
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     @SystemApi
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void setCallForwarding(@NonNull CallForwardingInfo callForwardingInfo,
             @Nullable @CallbackExecutor Executor executor,
             @Nullable @CallForwardingInfoCallback.CallForwardingError
@@ -14912,6 +15108,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void getCallWaitingStatus(@NonNull Executor executor,
             @NonNull @CallWaitingStatus Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
@@ -14960,6 +15157,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
     public void setCallWaitingEnabled(boolean enabled, @Nullable Executor executor,
             @Nullable Consumer<Integer> resultListener) {
         if (resultListener != null) {
@@ -15041,6 +15239,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public void setMobileDataPolicyEnabled(@MobileDataPolicy int policy, boolean enabled) {
         try {
             ITelephony service = getITelephony();
@@ -15061,6 +15260,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_DATA)
     public boolean isMobileDataPolicyEnabled(@MobileDataPolicy int policy) {
         try {
             ITelephony service = getITelephony();
@@ -15095,6 +15295,7 @@
      */
     @WorkerThread
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     @SystemApi
     public boolean isIccLockEnabled() {
         try {
@@ -15129,6 +15330,7 @@
     @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public PinResult setIccLockEnabled(boolean enabled, @NonNull String pin) {
         checkNotNull(pin, "setIccLockEnabled pin can't be null.");
         try {
@@ -15170,6 +15372,7 @@
     @SystemApi
     @NonNull
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public PinResult changeIccLockPin(@NonNull String oldPin, @NonNull String newPin) {
         checkNotNull(oldPin, "changeIccLockPin oldPin can't be null.");
         checkNotNull(newPin, "changeIccLockPin newPin can't be null.");
@@ -15562,6 +15765,7 @@
      *
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public @NonNull List<String> getEquivalentHomePlmns() {
         try {
             ITelephony telephony = getITelephony();
@@ -15675,6 +15879,7 @@
      * @param capability the name of the capability to check for
      * @return the availability of the capability
      */
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public boolean isRadioInterfaceCapabilitySupported(
             @NonNull @RadioInterfaceCapability String capability) {
         try {
@@ -15796,6 +16001,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     @ThermalMitigationResult
     public int sendThermalMitigationRequest(
             @NonNull ThermalMitigationRequest thermalMitigationRequest) {
@@ -16067,6 +16273,7 @@
     @WorkerThread
     @RequiresPermission(anyOf = {android.Manifest.permission.MODIFY_PHONE_STATE,
             Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION})
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
     public void bootstrapAuthenticationRequest(
             @UiccAppTypeExt int appType, @NonNull Uri nafId,
             @NonNull UaSecurityProtocolIdentifier securityProtocol,
@@ -16161,6 +16368,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void setSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
         Objects.requireNonNull(request, "request must not be null");
 
@@ -16190,6 +16398,7 @@
      */
     @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
     public void clearSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) {
         Objects.requireNonNull(request, "request must not be null");
 
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 122662d..e0c5298 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -19,6 +19,8 @@
 import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -42,6 +44,7 @@
 /**
  * Manages the radio access network scan requests and callbacks.
  */
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS)
 public final class TelephonyScanManager {
 
     private static final String TAG = "TelephonyScanManager";
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index b0ddf2c..a710e38 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1290,8 +1290,8 @@
                 && Objects.equals(this.mOperatorNumeric, other.mOperatorNumeric)
                 && Objects.equals(this.mProtocol, other.mProtocol)
                 && Objects.equals(this.mRoamingProtocol, other.mRoamingProtocol)
-                && xorEqualsInt(this.mMtuV4, other.mMtuV4)
-                && xorEqualsInt(this.mMtuV6, other.mMtuV6)
+                && mtuUnsetOrEquals(this.mMtuV4, other.mMtuV4)
+                && mtuUnsetOrEquals(this.mMtuV6, other.mMtuV6)
                 && Objects.equals(this.mCarrierEnabled, other.mCarrierEnabled)
                 && Objects.equals(this.mNetworkTypeBitmask, other.mNetworkTypeBitmask)
                 && Objects.equals(this.mLingeringNetworkTypeBitmask,
@@ -1319,7 +1319,12 @@
     // Equal or one is not specified.
     private boolean xorEqualsInt(int first, int second) {
         return first == UNSPECIFIED_INT || second == UNSPECIFIED_INT
-            || Objects.equals(first, second);
+                || first == second;
+    }
+
+    // Equal or one is not specified. Specific to MTU where <= 0 indicates unset.
+    private boolean mtuUnsetOrEquals(int first, int second) {
+        return first <= 0 || second <= 0 || first == second;
     }
 
     private String nullToEmpty(String stringValue) {
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index ab35d77..4452d1c 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -19,8 +19,10 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.service.euicc.EuiccProfileInfo;
@@ -61,6 +63,7 @@
  * @hide
  */
 @SystemApi
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC)
 public class EuiccCardManager {
     private static final String TAG = "EuiccCardManager";
 
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index a1e4f29..a49a61b5 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
@@ -54,6 +55,7 @@
  *
  * <p>See {@link #isEnabled} before attempting to use these APIs.
  */
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_EUICC)
 public class EuiccManager {
 
     /**
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 82d64ab..5bae1ad 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -21,11 +21,13 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SuppressAutoDoc;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
@@ -61,6 +63,7 @@
  * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this
  * manager.
  */
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
 public class ImsMmTelManager implements RegistrationManager {
     private static final String TAG = "ImsMmTelManager";
 
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 1b047c7..3415868 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -19,11 +19,13 @@
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -53,6 +55,7 @@
  *
  * Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this manager.
  */
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
 public class ImsRcsManager {
     private static final String TAG = "ImsRcsManager";
 
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 5aef8a6..677c1a9 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -20,6 +20,7 @@
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.StringDef;
@@ -55,6 +56,7 @@
  * applications and may vary. It is up to the carrier and OEM applications to ensure that the
  * correct provisioning keys are being used when integrating with a vendor's ImsService.
  */
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
 public class ProvisioningManager {
 
     private static final String TAG = "ProvisioningManager";
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index a2015cd..090d413 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -21,7 +21,9 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -42,6 +44,7 @@
 /**
  * Manages IMS Service registration state for associated {@link ImsFeature}s.
  */
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS)
 public interface RegistrationManager {
 
     /**
diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java
index f913df5..94e9afb 100644
--- a/telephony/java/android/telephony/ims/SipDelegateManager.java
+++ b/telephony/java/android/telephony/ims/SipDelegateManager.java
@@ -21,6 +21,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
@@ -57,6 +58,7 @@
  * @hide
  */
 @SystemApi
+@RequiresFeature(PackageManager.FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION)
 public class SipDelegateManager {
 
     /**
diff --git a/tests/ApkVerityTest/AndroidTest.xml b/tests/ApkVerityTest/AndroidTest.xml
index 55704ed..3c8e1ed 100644
--- a/tests/ApkVerityTest/AndroidTest.xml
+++ b/tests/ApkVerityTest/AndroidTest.xml
@@ -35,6 +35,8 @@
         <option name="push" value="ApkVerityTestCert.der->/data/local/tmp/ApkVerityTestCert.der" />
     </target_preparer>
 
+    <!-- Skip on HWASan. TODO(b/232288278): Re-enable -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.SkipHWASanModuleController" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="ApkVerityTest.jar" />
     </test>
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
index 82a5dac..7059c52 100644
--- a/tools/processors/intdef_mappings/Android.bp
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -7,18 +7,24 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
+java_library_host {
+    name: "libintdef-annotation-processor",
+
+    srcs: [
+        ":framework-annotations",
+        "src/**/*.java",
+        "src/**/*.kt",
+    ],
+
+    use_tools_jar: true,
+}
+
 java_plugin {
     name: "intdef-annotation-processor",
 
     processor_class: "android.processor.IntDefProcessor",
 
-    srcs: [
-        ":framework-annotations",
-        "src/**/*.java",
-        "src/**/*.kt"
-    ],
-
-    use_tools_jar: true,
+    static_libs: ["libintdef-annotation-processor"],
 }
 
 java_test_host {
@@ -26,8 +32,8 @@
 
     srcs: [
         "test/**/*.java",
-        "test/**/*.kt"
-     ],
+        "test/**/*.kt",
+    ],
     java_resource_dirs: ["test/resources"],
 
     static_libs: [
@@ -35,7 +41,7 @@
         "truth-prebuilt",
         "junit",
         "guava",
-        "intdef-annotation-processor"
+        "libintdef-annotation-processor",
     ],
 
     test_suites: ["general-tests"],
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index ea9974f..877a1d2 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -7,10 +7,8 @@
     default_applicable_licenses: ["frameworks_base_license"],
 }
 
-java_plugin {
-    name: "view-inspector-annotation-processor",
-
-    processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+java_library_host {
+    name: "libview-inspector-annotation-processor",
 
     srcs: ["src/java/**/*.java"],
     java_resource_dirs: ["src/resources"],
@@ -23,6 +21,16 @@
     use_tools_jar: true,
 }
 
+java_plugin {
+    name: "view-inspector-annotation-processor",
+
+    processor_class: "android.processor.view.inspector.PlatformInspectableProcessor",
+
+    static_libs: [
+        "libview-inspector-annotation-processor",
+    ],
+}
+
 java_test_host {
     name: "view-inspector-annotation-processor-test",
 
@@ -32,7 +40,7 @@
     static_libs: [
         "junit",
         "guava",
-        "view-inspector-annotation-processor"
+        "libview-inspector-annotation-processor",
     ],
 
     test_suites: ["general-tests"],