diff options
35 files changed, 584 insertions, 512 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 02fee102b4c3..bd693850f45e 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -13,6 +13,8 @@ // limitations under the License. aconfig_srcjars = [ + // !!! KEEP THIS LIST ALPHABETICAL !!! + ":aconfig_mediacodec_flags_java_lib{.generated_srcjars}", ":android.content.pm.flags-aconfig-java{.generated_srcjars}", ":android.content.res.flags-aconfig-java{.generated_srcjars}", ":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}", @@ -21,10 +23,11 @@ aconfig_srcjars = [ ":android.os.flags-aconfig-java{.generated_srcjars}", ":android.security.flags-aconfig-java{.generated_srcjars}", ":com.android.hardware.camera2-aconfig-java{.generated_srcjars}", - ":com.android.window.flags.window-aconfig-java{.generated_srcjars}", ":com.android.hardware.input-aconfig-java{.generated_srcjars}", - ":com.android.text.flags-aconfig-java{.generated_srcjars}", ":com.android.net.flags-aconfig-java{.generated_srcjars}", + ":com.android.text.flags-aconfig-java{.generated_srcjars}", + ":com.android.window.flags.window-aconfig-java{.generated_srcjars}", + // !!! KEEP THIS LIST ALPHABETICAL !!! ] filegroup { diff --git a/Android.bp b/Android.bp index 5f02a15ad185..2113e4b85248 100644 --- a/Android.bp +++ b/Android.bp @@ -205,7 +205,6 @@ java_library { "apex_aidl_interface-java", "packagemanager_aidl-java", "framework-protos", - "libtombstone_proto_java", "updatable-driver-protos", "ota_metadata_proto_java", "android.hidl.base-V1.0-java", diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp index d03bbd249b00..e7adf203334e 100644 --- a/ProtoLibraries.bp +++ b/ProtoLibraries.bp @@ -34,6 +34,7 @@ gensrcs { ":ipconnectivity-proto-src", ":libstats_atom_enum_protos", ":libstats_atom_message_protos", + ":libtombstone_proto-src", "core/proto/**/*.proto", "libs/incident/**/*.proto", ], diff --git a/STABILITY_OWNERS b/STABILITY_OWNERS deleted file mode 100644 index a7ecb4dfdd44..000000000000 --- a/STABILITY_OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -gaillard@google.com - diff --git a/core/api/current.txt b/core/api/current.txt index 48f58c09871d..b6b8b6e65cd3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -23631,6 +23631,7 @@ package android.media { field public static final String KEY_HDR10_PLUS_INFO = "hdr10-plus-info"; field public static final String KEY_HDR_STATIC_INFO = "hdr-static-info"; field public static final String KEY_HEIGHT = "height"; + field @FlaggedApi("com.android.media.codec.flags.codec_importance") public static final String KEY_IMPORTANCE = "importance"; field public static final String KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period"; field public static final String KEY_IS_ADTS = "is-adts"; field public static final String KEY_IS_AUTOSELECT = "is-autoselect"; diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java index ec181dac6b36..27f6a266597c 100644 --- a/core/java/android/appwidget/AppWidgetHostView.java +++ b/core/java/android/appwidget/AppWidgetHostView.java @@ -156,22 +156,6 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW } /** - * @hide - */ - public static class AdapterChildHostView extends AppWidgetHostView { - - public AdapterChildHostView(Context context) { - super(context); - } - - @Override - public Context getRemoteContextEnsuringCorrectCachedApkPath() { - // To reduce noise in error messages - return null; - } - } - - /** * Set the AppWidget that will be displayed by this view. This method also adds default padding * to widgets, as described in {@link #getDefaultPaddingForWidget(Context, ComponentName, Rect)} * and can be overridden in order to add custom padding. @@ -937,31 +921,17 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW setColorResources(RemoteViews.ColorResources.create(mContext, colorMapping)); } - private void setColorResourcesStates(RemoteViews.ColorResources colorResources) { - mColorResources = colorResources; - mColorMappingChanged = true; - mViewMode = VIEW_MODE_NOINIT; - } - /** @hide **/ public void setColorResources(RemoteViews.ColorResources colorResources) { if (colorResources == mColorResources) { return; } - setColorResourcesStates(colorResources); + mColorResources = colorResources; + mColorMappingChanged = true; + mViewMode = VIEW_MODE_NOINIT; reapplyLastRemoteViews(); } - /** - * @hide - */ - public void setColorResourcesNoReapply(RemoteViews.ColorResources colorResources) { - if (colorResources == mColorResources) { - return; - } - setColorResourcesStates(colorResources); - } - /** Check if, in the current context, the two color mappings are equivalent. */ private boolean isSameColorMapping(SparseIntArray oldColors, SparseIntArray newColors) { if (oldColors.size() != newColors.size()) { diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index 30524a1132fa..1994058441d5 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -53,7 +53,7 @@ flag { flag { name: "frp_enforcement" - namespace: "android_hw_security" + namespace: "hardware_backed_security" description: "This flag controls whether PDB enforces FRP" bug: "290312729" is_fixed_read_only: true diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java index 7694754de6ff..c9ffdae890c5 100644 --- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java +++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java @@ -49,7 +49,6 @@ import android.view.KeyEvent; import android.view.View; import android.view.ViewRootImpl; -import com.android.internal.annotations.GuardedBy; import com.android.internal.infra.AndroidFuture; import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection; import com.android.internal.inputmethod.IRemoteInputConnection; @@ -60,6 +59,7 @@ import java.lang.annotation.Retention; import java.lang.ref.WeakReference; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.function.Supplier; @@ -164,18 +164,15 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { boolean cancellable(); } - @GuardedBy("mLock") - @Nullable - private InputConnection mInputConnection; + @NonNull + private final AtomicReference<InputConnection> mInputConnectionRef; + @NonNull + private final AtomicBoolean mDeactivateRequested = new AtomicBoolean(false); @NonNull private final Looper mLooper; private final Handler mH; - private final Object mLock = new Object(); - @GuardedBy("mLock") - private boolean mFinished = false; - private final InputMethodManager mParentInputMethodManager; private final WeakReference<View> mServedView; @@ -193,7 +190,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { RemoteInputConnectionImpl(@NonNull Looper looper, @NonNull InputConnection inputConnection, @NonNull InputMethodManager inputMethodManager, @Nullable View servedView) { - mInputConnection = inputConnection; + mInputConnectionRef = new AtomicReference<>(inputConnection); mLooper = looper; mH = new Handler(mLooper); mParentInputMethodManager = inputMethodManager; @@ -211,9 +208,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { */ @Nullable public InputConnection getInputConnection() { - synchronized (mLock) { - return mInputConnection; - } + return mInputConnectionRef.get(); } /** @@ -229,13 +224,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { * {@link InputConnection#closeConnection()} as a result of {@link #deactivate()}. */ private boolean isFinished() { - synchronized (mLock) { - return mFinished; - } - } - - private boolean isActive() { - return mParentInputMethodManager.isActive() && !isFinished(); + return mInputConnectionRef.get() == null; } private View getServedView() { @@ -372,28 +361,18 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { */ @Dispatching(cancellable = false) public void deactivate() { - if (isFinished()) { + if (mDeactivateRequested.getAndSet(true)) { // This is a small performance optimization. Still only the 1st call of - // reportFinish() will take effect. + // deactivate() will take effect. return; } dispatch(() -> { // Deactivate the notifier when finishing typing. notifyTypingHint(false /* isTyping */, true /* deactivate */); - // Note that we do not need to worry about race condition here, because 1) mFinished is - // updated only inside this block, and 2) the code here is running on a Handler hence we - // assume multiple closeConnection() tasks will not be handled at the same time. - if (isFinished()) { - return; - } Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#closeConnection"); try { InputConnection ic = getInputConnection(); - // Note we do NOT check isActive() here, because this is safe - // for an IME to call at any time, and we need to allow it - // through to clean up our state after the IME has switched to - // another client. if (ic == null) { return; } @@ -403,10 +382,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { // TODO(b/199934664): See if we can remove this by providing a default impl. } } finally { - synchronized (mLock) { - mInputConnection = null; - mFinished = true; - } + mInputConnectionRef.set(null); Trace.traceEnd(Trace.TRACE_TAG_INPUT); } @@ -460,8 +436,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { public String toString() { return "RemoteInputConnectionImpl{" + "connection=" + getInputConnection() - + " finished=" + isFinished() - + " mParentInputMethodManager.isActive()=" + mParentInputMethodManager.isActive() + + " mDeactivateRequested=" + mDeactivateRequested.get() + " mServedView=" + mServedView.get() + "}"; } @@ -474,16 +449,14 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { * {@link DumpableInputConnection#dumpDebug(ProtoOutputStream, long)}. */ public void dumpDebug(ProtoOutputStream proto, long fieldId) { - synchronized (mLock) { - // Check that the call is initiated in the target thread of the current InputConnection - // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are - // executed on this thread. Otherwise the messages are dispatched to the correct thread - // in IInputConnectionWrapper, but this is not wanted while dumpng, for performance - // reasons. - if ((mInputConnection instanceof DumpableInputConnection) - && mLooper.isCurrentThread()) { - ((DumpableInputConnection) mInputConnection).dumpDebug(proto, fieldId); - } + final InputConnection ic = mInputConnectionRef.get(); + // Check that the call is initiated in the target thread of the current InputConnection + // {@link InputConnection#getHandler} since the messages to IInputConnectionWrapper are + // executed on this thread. Otherwise the messages are dispatched to the correct thread + // in IInputConnectionWrapper, but this is not wanted while dumping, for performance + // reasons. + if ((ic instanceof DumpableInputConnection) && mLooper.isCurrentThread()) { + ((DumpableInputConnection) ic).dumpDebug(proto, fieldId); } } @@ -498,7 +471,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { public void dispatchReportFullscreenMode(boolean enabled) { dispatch(() -> { final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { return; } ic.reportFullscreenMode(enabled); @@ -514,7 +487,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return null; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getTextAfterCursor on inactive InputConnection"); return null; } @@ -536,7 +509,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return null; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getTextBeforeCursor on inactive InputConnection"); return null; } @@ -558,7 +531,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return null; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getSelectedText on inactive InputConnection"); return null; } @@ -580,7 +553,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return null; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getSurroundingText on inactive InputConnection"); return null; } @@ -608,7 +581,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return 0; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getCursorCapsMode on inactive InputConnection"); return 0; } @@ -625,7 +598,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return null; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getExtractedText on inactive InputConnection"); return null; } @@ -642,7 +615,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "commitText on inactive InputConnection"); return; } @@ -660,7 +633,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "commitText on inactive InputConnection"); return; } @@ -676,7 +649,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "commitCompletion on inactive InputConnection"); return; } @@ -692,7 +665,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "commitCorrection on inactive InputConnection"); return; } @@ -712,7 +685,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "setSelection on inactive InputConnection"); return; } @@ -728,7 +701,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "performEditorAction on inactive InputConnection"); return; } @@ -744,7 +717,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "performContextMenuAction on inactive InputConnection"); return; } @@ -760,7 +733,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "setComposingRegion on inactive InputConnection"); return; } @@ -781,7 +754,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "setComposingRegion on inactive InputConnection"); return; } @@ -798,7 +771,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "setComposingText on inactive InputConnection"); return; } @@ -816,7 +789,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "setComposingText on inactive InputConnection"); return; } @@ -845,11 +818,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - // Note we do NOT check isActive() here, because this is safe - // for an IME to call at any time, and we need to allow it - // through to clean up our state after the IME has switched to - // another client. - if (ic == null) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "finishComposingTextFromImm on inactive InputConnection"); return; } @@ -873,11 +842,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - // Note we do NOT check isActive() here, because this is safe - // for an IME to call at any time, and we need to allow it - // through to clean up our state after the IME has switched to - // another client. - if (ic == null) { + if (ic == null && mDeactivateRequested.get()) { Log.w(TAG, "finishComposingText on inactive InputConnection"); return; } @@ -893,7 +858,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "sendKeyEvent on inactive InputConnection"); return; } @@ -909,7 +874,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "clearMetaKeyStates on inactive InputConnection"); return; } @@ -926,7 +891,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "deleteSurroundingText on inactive InputConnection"); return; } @@ -944,7 +909,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "deleteSurroundingTextInCodePoints on inactive InputConnection"); return; } @@ -964,7 +929,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "beginBatchEdit on inactive InputConnection"); return; } @@ -980,7 +945,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "endBatchEdit on inactive InputConnection"); return; } @@ -996,7 +961,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "performSpellCheck on inactive InputConnection"); return; } @@ -1013,7 +978,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "performPrivateCommand on inactive InputConnection"); return; } @@ -1051,7 +1016,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "performHandwritingGesture on inactive InputConnection"); if (resultReceiver != null) { resultReceiver.send( @@ -1091,7 +1056,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "previewHandwritingGesture on inactive InputConnection"); return; // cancelled } @@ -1139,7 +1104,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { @InputConnection.CursorUpdateMode int cursorUpdateMode, @InputConnection.CursorUpdateFilter int cursorUpdateFilter, int imeDisplayId) { final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "requestCursorUpdates on inactive InputConnection"); return false; } @@ -1177,7 +1142,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "requestTextBoundsInfo on inactive InputConnection"); resultReceiver.send(TextBoundsInfoResult.CODE_CANCELLED, null); return; @@ -1221,7 +1186,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return false; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "commitContent on inactive InputConnection"); return false; } @@ -1246,7 +1211,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "setImeConsumesInput on inactive InputConnection"); return; } @@ -1270,7 +1235,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "replaceText on inactive InputConnection"); return; } @@ -1289,7 +1254,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "commitText on inactive InputConnection"); return; } @@ -1309,7 +1274,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "setSelection on inactive InputConnection"); return; } @@ -1326,7 +1291,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return null; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getSurroundingText on inactive InputConnection"); return null; } @@ -1354,7 +1319,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "deleteSurroundingText on inactive InputConnection"); return; } @@ -1370,7 +1335,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "sendKeyEvent on inactive InputConnection"); return; } @@ -1386,7 +1351,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "performEditorAction on inactive InputConnection"); return; } @@ -1402,7 +1367,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "performContextMenuAction on inactive InputConnection"); return; } @@ -1419,7 +1384,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return 0; // cancelled } final InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "getCursorCapsMode on inactive InputConnection"); return 0; } @@ -1435,7 +1400,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub { return; // cancelled } InputConnection ic = getInputConnection(); - if (ic == null || !isActive()) { + if (ic == null || mDeactivateRequested.get()) { Log.w(TAG, "clearMetaKeyStates on inactive InputConnection"); return; } diff --git a/core/java/android/widget/RemoteCollectionItemsAdapter.java b/core/java/android/widget/RemoteCollectionItemsAdapter.java index 9b396aeea9eb..d84330828bf7 100644 --- a/core/java/android/widget/RemoteCollectionItemsAdapter.java +++ b/core/java/android/widget/RemoteCollectionItemsAdapter.java @@ -18,7 +18,6 @@ package android.widget; import android.annotation.NonNull; import android.annotation.Nullable; -import android.appwidget.AppWidgetHostView; import android.util.SparseIntArray; import android.view.View; import android.view.ViewGroup; @@ -26,6 +25,8 @@ import android.widget.RemoteViews.ColorResources; import android.widget.RemoteViews.InteractionHandler; import android.widget.RemoteViews.RemoteCollectionItems; +import com.android.internal.R; + import java.util.stream.IntStream; /** @@ -177,14 +178,40 @@ class RemoteCollectionItemsAdapter extends BaseAdapter { RemoteViews item = mItems.getItemView(position); item.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD); + View reapplyView = getViewToReapply(convertView, item); + + // Reapply the RemoteViews if we can. + if (reapplyView != null) { + try { + item.reapply( + parent.getContext(), + reapplyView, + mInteractionHandler, + null /* size */, + mColorResources); + return reapplyView; + } catch (RuntimeException e) { + // We can't reapply for some reason, we'll fallback to an apply and inflate a + // new view. + } + } + + return item.apply( + parent.getContext(), + parent, + mInteractionHandler, + null /* size */, + mColorResources); + } + + /** Returns {@code convertView} if it can be used to reapply {@code item}, or null otherwise. */ + @Nullable + private static View getViewToReapply(@Nullable View convertView, @NonNull RemoteViews item) { + if (convertView == null) return null; + + Object layoutIdTag = convertView.getTag(R.id.widget_frame); + if (!(layoutIdTag instanceof Integer)) return null; - AppWidgetHostView newView = convertView instanceof AppWidgetHostView.AdapterChildHostView - widgetChildView - ? widgetChildView - : new AppWidgetHostView.AdapterChildHostView(parent.getContext()); - newView.setInteractionHandler(mInteractionHandler); - newView.setColorResourcesNoReapply(mColorResources); - newView.updateAppWidget(item); - return newView; + return item.getLayoutId() == (Integer) layoutIdTag ? convertView : null; } } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index eb3f96e7a652..a740b651142d 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -6913,13 +6913,13 @@ public class RemoteViews implements Parcelable, Filter { View parent = (View) view.getParent(); // Break the for loop on the first encounter of: // 1) an AdapterView, - // 2) an AppWidgetHostView that is not a child of an adapter view, or + // 2) an AppWidgetHostView that is not a RemoteViewsFrameLayout, or // 3) a null parent. // 2) and 3) are unexpected and catch the case where a child is not // correctly parented in an AdapterView. while (parent != null && !(parent instanceof AdapterView<?>) && !((parent instanceof AppWidgetHostView) - && !(parent instanceof AppWidgetHostView.AdapterChildHostView))) { + && !(parent instanceof RemoteViewsAdapter.RemoteViewsFrameLayout))) { parent = (View) parent.getParent(); } diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index 2f28a8704cd3..61a7599e8f73 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -368,7 +368,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback * A FrameLayout which contains a loading view, and manages the re/applying of RemoteViews when * they are loaded. */ - static class RemoteViewsFrameLayout extends AppWidgetHostView.AdapterChildHostView { + static class RemoteViewsFrameLayout extends AppWidgetHostView { private final FixedSizeRemoteViewsCache mCache; public int cacheIndex = -1; @@ -408,6 +408,11 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } @Override + protected Context getRemoteContextEnsuringCorrectCachedApkPath() { + return null; + } + + @Override protected View getErrorView() { // Use the default loading view as the error view. return getDefaultView(); diff --git a/core/java/com/android/internal/util/RingBuffer.java b/core/java/com/android/internal/util/RingBuffer.java index 8fc4c30e54ab..7f8c8a1cae04 100644 --- a/core/java/com/android/internal/util/RingBuffer.java +++ b/core/java/com/android/internal/util/RingBuffer.java @@ -19,7 +19,10 @@ package com.android.internal.util; import static com.android.internal.util.Preconditions.checkArgumentPositive; import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; import java.util.Arrays; +import java.util.function.IntFunction; +import java.util.function.Supplier; /** * A simple ring buffer structure with bounded capacity backed by an array. @@ -29,16 +32,35 @@ import java.util.Arrays; */ public class RingBuffer<T> { + private final Supplier<T> mNewItem; // Array for storing events. private final T[] mBuffer; // Cursor keeping track of the logical end of the array. This cursor never // wraps and instead keeps track of the total number of append() operations. private long mCursor = 0; + /** + * @deprecated This uses reflection to create new instances. + * Use {@link #RingBuffer(Supplier, IntFunction, int)}} instead. + */ + @Deprecated public RingBuffer(Class<T> c, int capacity) { + this(() -> (T) createNewItem(c), cap -> (T[]) Array.newInstance(c, cap), capacity); + } + + private static Object createNewItem(Class c) { + try { + return c.getDeclaredConstructor().newInstance(); + } catch (IllegalAccessException | InstantiationException | NoSuchMethodException + | InvocationTargetException e) { + return null; + } + } + + public RingBuffer(Supplier<T> newItem, IntFunction<T[]> newBacking, int capacity) { checkArgumentPositive(capacity, "A RingBuffer cannot have 0 capacity"); - // Java cannot create generic arrays without a runtime hint. - mBuffer = (T[]) Array.newInstance(c, capacity); + mBuffer = newBacking.apply(capacity); + mNewItem = newItem; } public int size() { @@ -68,22 +90,11 @@ public class RingBuffer<T> { public T getNextSlot() { final int nextSlotIdx = indexOf(mCursor++); if (mBuffer[nextSlotIdx] == null) { - mBuffer[nextSlotIdx] = createNewItem(); + mBuffer[nextSlotIdx] = mNewItem.get(); } return mBuffer[nextSlotIdx]; } - /** - * @return a new object of type <T> or null if a new object could not be created. - */ - protected T createNewItem() { - try { - return (T) mBuffer.getClass().getComponentType().newInstance(); - } catch (IllegalAccessException | InstantiationException e) { - return null; - } - } - public T[] toArray() { // Only generic way to create a T[] from another T[] T[] out = Arrays.copyOf(mBuffer, size(), (Class<T[]>) mBuffer.getClass()); diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java index 4ec5e1b67c5d..6404c4bc33d6 100644 --- a/keystore/java/android/security/Authorization.java +++ b/keystore/java/android/security/Authorization.java @@ -100,12 +100,14 @@ public class Authorization { * * @param userId - the user's Android user ID * @param unlockingSids - list of biometric SIDs with which the device may be unlocked again + * @param weakUnlockEnabled - true if non-strong biometric or trust agent unlock is enabled * @return 0 if successful or a {@code ResponseCode}. */ - public static int onDeviceLocked(int userId, @NonNull long[] unlockingSids) { + public static int onDeviceLocked(int userId, @NonNull long[] unlockingSids, + boolean weakUnlockEnabled) { StrictMode.noteDiskWrite(); try { - getService().onDeviceLocked(userId, unlockingSids); + getService().onDeviceLocked(userId, unlockingSids, weakUnlockEnabled); return 0; } catch (RemoteException | NullPointerException e) { Log.w(TAG, "Can not connect to keystore", e); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index cf31173d266e..56f1e64396af 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -115,7 +115,7 @@ IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw( const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler, - const HardwareBufferRenderParams& bufferParams) { + const HardwareBufferRenderParams& bufferParams, std::mutex& profilerLock) { if (!isCapturingSkp() && !mHardwareBuffer) { mEglManager.damageFrame(frame, dirty); } @@ -167,6 +167,7 @@ IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw( // Draw visual debugging features if (CC_UNLIKELY(Properties::showDirtyRegions || ProfileType::None != Properties::getProfileType())) { + std::scoped_lock lock(profilerLock); SkCanvas* profileCanvas = surface->getCanvas(); SkiaProfileRenderer profileRenderer(profileCanvas, frame.width(), frame.height()); profiler->draw(profileRenderer); diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h index f0461bef170c..0325593f7170 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h @@ -42,7 +42,8 @@ public: const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode> >& renderNodes, FrameInfoVisualizer* profiler, - const renderthread::HardwareBufferRenderParams& bufferParams) override; + const renderthread::HardwareBufferRenderParams& bufferParams, + std::mutex& profilerLock) override; GrSurfaceOrigin getSurfaceOrigin() override { return kBottomLeft_GrSurfaceOrigin; } bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index 86096d5bd01c..7d192321f13e 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -75,7 +75,7 @@ IRenderPipeline::DrawResult SkiaVulkanPipeline::draw( const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler, - const HardwareBufferRenderParams& bufferParams) { + const HardwareBufferRenderParams& bufferParams, std::mutex& profilerLock) { sk_sp<SkSurface> backBuffer; SkMatrix preTransform; if (mHardwareBuffer) { @@ -103,6 +103,7 @@ IRenderPipeline::DrawResult SkiaVulkanPipeline::draw( // Draw visual debugging features if (CC_UNLIKELY(Properties::showDirtyRegions || ProfileType::None != Properties::getProfileType())) { + std::scoped_lock lock(profilerLock); SkCanvas* profileCanvas = backBuffer->getCanvas(); SkAutoCanvasRestore saver(profileCanvas, true); profileCanvas->concat(mVkSurface->getCurrentPreTransform()); diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h index 284cde537ec0..37b86f136fbb 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h @@ -42,7 +42,8 @@ public: const LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode> >& renderNodes, FrameInfoVisualizer* profiler, - const renderthread::HardwareBufferRenderParams& bufferParams) override; + const renderthread::HardwareBufferRenderParams& bufferParams, + std::mutex& profilerLock) override; GrSurfaceOrigin getSurfaceOrigin() override { return kTopLeft_GrSurfaceOrigin; } bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) override; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 618c896afa96..f6907831e11f 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -592,14 +592,10 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { { // FrameInfoVisualizer accesses the frame events, which cannot be mutated mid-draw // or it can lead to memory corruption. - // This lock is overly broad, but it's the quickest fix since this mutex is otherwise - // not visible to IRenderPipeline much less FrameInfoVisualizer. And since this is - // the thread we're primarily concerned about being responsive, this being too broad - // shouldn't pose a performance issue. - std::scoped_lock lock(mFrameMetricsReporterMutex); drawResult = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue, mContentDrawBounds, mOpaque, - mLightInfo, mRenderNodes, &(profiler()), mBufferParams); + mLightInfo, mRenderNodes, &(profiler()), mBufferParams, + profilerLock()); } uint64_t frameCompleteNr = getFrameNumber(); @@ -729,7 +725,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { mCurrentFrameInfo->markFrameCompleted(); mCurrentFrameInfo->set(FrameInfoIndex::GpuCompleted) = mCurrentFrameInfo->get(FrameInfoIndex::FrameCompleted); - std::scoped_lock lock(mFrameMetricsReporterMutex); + std::scoped_lock lock(mFrameInfoMutex); mJankTracker.finishFrame(*mCurrentFrameInfo, mFrameMetricsReporter, frameCompleteNr, mSurfaceControlGenerationId); } @@ -758,7 +754,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { void CanvasContext::reportMetricsWithPresentTime() { { // acquire lock - std::scoped_lock lock(mFrameMetricsReporterMutex); + std::scoped_lock lock(mFrameInfoMutex); if (mFrameMetricsReporter == nullptr) { return; } @@ -793,7 +789,7 @@ void CanvasContext::reportMetricsWithPresentTime() { forthBehind->set(FrameInfoIndex::DisplayPresentTime) = presentTime; { // acquire lock - std::scoped_lock lock(mFrameMetricsReporterMutex); + std::scoped_lock lock(mFrameInfoMutex); if (mFrameMetricsReporter != nullptr) { mFrameMetricsReporter->reportFrameMetrics(forthBehind->data(), true /*hasPresentTime*/, frameNumber, surfaceControlId); @@ -802,7 +798,7 @@ void CanvasContext::reportMetricsWithPresentTime() { } void CanvasContext::addFrameMetricsObserver(FrameMetricsObserver* observer) { - std::scoped_lock lock(mFrameMetricsReporterMutex); + std::scoped_lock lock(mFrameInfoMutex); if (mFrameMetricsReporter.get() == nullptr) { mFrameMetricsReporter.reset(new FrameMetricsReporter()); } @@ -816,7 +812,7 @@ void CanvasContext::addFrameMetricsObserver(FrameMetricsObserver* observer) { } void CanvasContext::removeFrameMetricsObserver(FrameMetricsObserver* observer) { - std::scoped_lock lock(mFrameMetricsReporterMutex); + std::scoped_lock lock(mFrameInfoMutex); if (mFrameMetricsReporter.get() != nullptr) { mFrameMetricsReporter->removeObserver(observer); if (!mFrameMetricsReporter->hasObservers()) { @@ -853,7 +849,7 @@ void CanvasContext::onSurfaceStatsAvailable(void* context, int32_t surfaceContro FrameInfo* frameInfo = instance->getFrameInfoFromLast4(frameNumber, surfaceControlId); if (frameInfo != nullptr) { - std::scoped_lock lock(instance->mFrameMetricsReporterMutex); + std::scoped_lock lock(instance->mFrameInfoMutex); frameInfo->set(FrameInfoIndex::FrameCompleted) = std::max(gpuCompleteTime, frameInfo->get(FrameInfoIndex::SwapBuffersCompleted)); frameInfo->set(FrameInfoIndex::GpuCompleted) = std::max( diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 32ac5af94c14..3978fbcc3a21 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -161,6 +161,7 @@ public: void notifyFramePending(); FrameInfoVisualizer& profiler() { return mProfiler; } + std::mutex& profilerLock() { return mFrameInfoMutex; } void dumpFrames(int fd); void resetFrameStats(); @@ -340,8 +341,8 @@ private: JankTracker mJankTracker; FrameInfoVisualizer mProfiler; std::unique_ptr<FrameMetricsReporter> mFrameMetricsReporter - GUARDED_BY(mFrameMetricsReporterMutex); - std::mutex mFrameMetricsReporterMutex; + GUARDED_BY(mFrameInfoMutex); + std::mutex mFrameInfoMutex; std::set<RenderNode*> mPrefetchedLayers; diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h index 6c2cb9d71c55..023c29a3ab85 100644 --- a/libs/hwui/renderthread/IRenderPipeline.h +++ b/libs/hwui/renderthread/IRenderPipeline.h @@ -67,7 +67,8 @@ public: const Rect& contentDrawBounds, bool opaque, const LightInfo& lightInfo, const std::vector<sp<RenderNode>>& renderNodes, FrameInfoVisualizer* profiler, - const HardwareBufferRenderParams& bufferParams) = 0; + const HardwareBufferRenderParams& bufferParams, + std::mutex& profilerLock) = 0; virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) = 0; virtual DeferredLayerUpdater* createTextureLayer() = 0; diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 46db77708521..587e35b4b1fc 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -16,6 +16,9 @@ package android.media; +import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE; + +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1635,6 +1638,34 @@ public final class MediaFormat { */ public static final String KEY_ALLOW_FRAME_DROP = "allow-frame-drop"; + /** + * A key describing the desired codec importance for the application. + * <p> + * The associated value is a positive integer including zero. + * Higher value means lesser importance. + * <p> + * The resource manager may use the codec importance, along with other factors + * when reclaiming codecs from an application. + * The specifics of reclaim policy is device dependent, but specifying the codec importance, + * will allow the resource manager to prioritize reclaiming less important codecs + * (assigned higher values) from the (reclaim) requesting application first. + * So, the codec importance is only relevant within the context of that application. + * <p> + * The codec importance can be set: + * <ul> + * <li>through {@link MediaCodec#configure}. </li> + * <li>through {@link MediaCodec#setParameters} if the codec has been configured already, + * which allows the users to change the codec importance multiple times. + * </ul> + * Any change/update in codec importance is guaranteed upon the completion of the function call + * that sets the codec importance. So, in case of concurrent codec operations, + * make sure to wait for the change in codec importance, before using another codec. + * Note that unless specified, by default the codecs will have highest importance (of value 0). + * + */ + @FlaggedApi(FLAG_CODEC_IMPORTANCE) + public static final String KEY_IMPORTANCE = "importance"; + /* package private */ MediaFormat(@NonNull Map<String, Object> map) { mMap = map; } diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java index 5cdfca7392e3..926d7a4d3ea6 100644 --- a/services/core/java/com/android/server/BootReceiver.java +++ b/services/core/java/com/android/server/BootReceiver.java @@ -48,8 +48,6 @@ import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; import com.android.server.am.DropboxRateLimiter; -import com.android.server.os.TombstoneProtos; -import com.android.server.os.TombstoneProtos.Tombstone; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -62,14 +60,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.attribute.PosixFilePermissions; -import java.util.AbstractMap; import java.util.HashMap; import java.util.Iterator; -import java.util.Map; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; /** * Performs a number of miscellaneous, non-system-critical actions @@ -332,12 +327,12 @@ public class BootReceiver extends BroadcastReceiver { * * @param ctx Context * @param tombstone path to the tombstone - * @param tombstoneProto the parsed proto tombstone + * @param proto whether the tombstone is stored as proto * @param processName the name of the process corresponding to the tombstone * @param tmpFileLock the lock for reading/writing tmp files */ public static void addTombstoneToDropBox( - Context ctx, File tombstone, Tombstone tombstoneProto, String processName, + Context ctx, File tombstone, boolean proto, String processName, ReentrantLock tmpFileLock) { final DropBoxManager db = ctx.getSystemService(DropBoxManager.class); if (db == null) { @@ -347,33 +342,31 @@ public class BootReceiver extends BroadcastReceiver { // Check if we should rate limit and abort early if needed. DropboxRateLimiter.RateLimitResult rateLimitResult = - sDropboxRateLimiter.shouldRateLimit(TAG_TOMBSTONE_PROTO_WITH_HEADERS, processName); + sDropboxRateLimiter.shouldRateLimit( + proto ? TAG_TOMBSTONE_PROTO_WITH_HEADERS : TAG_TOMBSTONE, processName); if (rateLimitResult.shouldRateLimit()) return; HashMap<String, Long> timestamps = readTimestamps(); try { - // Remove the memory data from the proto. - Tombstone tombstoneProtoWithoutMemory = removeMemoryFromTombstone(tombstoneProto); - - final byte[] tombstoneBytes = tombstoneProtoWithoutMemory.toByteArray(); - - // Use JNI to call the c++ proto to text converter and add the headers to the tombstone. - String tombstoneWithoutMemory = new StringBuilder(getBootHeadersToLogAndUpdate()) - .append(rateLimitResult.createHeader()) - .append(getTombstoneText(tombstoneBytes)) - .toString(); - - // Add the tombstone without memory data to dropbox. - db.addText(TAG_TOMBSTONE, tombstoneWithoutMemory); - - // Add the tombstone proto to dropbox. - if (recordFileTimestamp(tombstone, timestamps)) { - tmpFileLock.lock(); - try { - addAugmentedProtoToDropbox(tombstone, tombstoneBytes, db, rateLimitResult); - } finally { - tmpFileLock.unlock(); + if (proto) { + if (recordFileTimestamp(tombstone, timestamps)) { + // We need to attach the count indicating the number of dropped dropbox entries + // due to rate limiting. Do this by enclosing the proto tombsstone in a + // container proto that has the dropped entry count and the proto tombstone as + // bytes (to avoid the complexity of reading and writing nested protos). + tmpFileLock.lock(); + try { + addAugmentedProtoToDropbox(tombstone, db, rateLimitResult); + } finally { + tmpFileLock.unlock(); + } } + } else { + // Add the header indicating how many events have been dropped due to rate limiting. + final String headers = getBootHeadersToLogAndUpdate() + + rateLimitResult.createHeader(); + addFileToDropBox(db, timestamps, headers, tombstone.getPath(), LOG_SIZE, + TAG_TOMBSTONE); } } catch (IOException e) { Slog.e(TAG, "Can't log tombstone", e); @@ -382,8 +375,11 @@ public class BootReceiver extends BroadcastReceiver { } private static void addAugmentedProtoToDropbox( - File tombstone, byte[] tombstoneBytes, DropBoxManager db, + File tombstone, DropBoxManager db, DropboxRateLimiter.RateLimitResult rateLimitResult) throws IOException { + // Read the proto tombstone file as bytes. + final byte[] tombstoneBytes = Files.readAllBytes(tombstone.toPath()); + final File tombstoneProtoWithHeaders = File.createTempFile( tombstone.getName(), ".tmp", TOMBSTONE_TMP_DIR); Files.setPosixFilePermissions( @@ -416,8 +412,6 @@ public class BootReceiver extends BroadcastReceiver { } } - private static native String getTombstoneText(byte[] tombstoneBytes); - private static void addLastkToDropBox( DropBoxManager db, HashMap<String, Long> timestamps, String headers, String footers, String filename, int maxSize, @@ -435,31 +429,6 @@ public class BootReceiver extends BroadcastReceiver { addFileWithFootersToDropBox(db, timestamps, headers, footers, filename, maxSize, tag); } - /** Removes memory information from the Tombstone proto. */ - @VisibleForTesting - public static Tombstone removeMemoryFromTombstone(Tombstone tombstoneProto) { - Tombstone.Builder tombstoneBuilder = tombstoneProto.toBuilder() - .clearMemoryMappings() - .clearThreads() - .putAllThreads(tombstoneProto.getThreadsMap().entrySet() - .stream() - .map(BootReceiver::clearMemoryDump) - .collect(Collectors.toMap(e->e.getKey(), e->e.getValue()))); - - if (tombstoneProto.hasSignalInfo()) { - tombstoneBuilder.setSignalInfo( - tombstoneProto.getSignalInfo().toBuilder().clearFaultAdjacentMetadata()); - } - - return tombstoneBuilder.build(); - } - - private static AbstractMap.SimpleEntry<Integer, TombstoneProtos.Thread> clearMemoryDump( - Map.Entry<Integer, TombstoneProtos.Thread> e) { - return new AbstractMap.SimpleEntry<Integer, TombstoneProtos.Thread>( - e.getKey(), e.getValue().toBuilder().clearMemoryDump().build()); - } - private static void addFileToDropBox( DropBoxManager db, HashMap<String, Long> timestamps, String headers, String filename, int maxSize, String tag) throws IOException { diff --git a/services/core/java/com/android/server/net/NetworkPolicyLogger.java b/services/core/java/com/android/server/net/NetworkPolicyLogger.java index 4d19eade5a05..d7188c7f10c6 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyLogger.java +++ b/services/core/java/com/android/server/net/NetworkPolicyLogger.java @@ -42,7 +42,6 @@ import android.util.ArraySet; import android.util.Log; import android.util.Slog; -import com.android.internal.annotations.Keep; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.RingBuffer; import com.android.server.am.ProcessList; @@ -414,7 +413,7 @@ public class NetworkPolicyLogger { private static final Date sDate = new Date(); public LogBuffer(int capacity) { - super(Data.class, capacity); + super(Data::new, Data[]::new, capacity); } public void uidStateChanged(int uid, int procState, long procStateSeq, @@ -690,12 +689,8 @@ public class NetworkPolicyLogger { /** * Container class for all networkpolicy events data. - * - * Note: This class needs to be public for RingBuffer class to be able to create - * new instances of this. */ - @Keep - public static final class Data { + private static final class Data { public int type; public long timeStamp; diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java index b7e737448d2d..ab0d0d2626db 100644 --- a/services/core/java/com/android/server/os/NativeTombstoneManager.java +++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java @@ -41,13 +41,14 @@ import android.system.Os; import android.system.StructStat; import android.util.Slog; import android.util.SparseArray; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoParseException; import com.android.internal.annotations.GuardedBy; import com.android.server.BootReceiver; import com.android.server.ServiceThread; import com.android.server.os.TombstoneProtos.Cause; import com.android.server.os.TombstoneProtos.Tombstone; -import com.android.server.os.protobuf.CodedInputStream; import libcore.io.IoUtils; @@ -127,21 +128,18 @@ public final class NativeTombstoneManager { return; } + String processName = "UNKNOWN"; final boolean isProtoFile = filename.endsWith(".pb"); - if (!isProtoFile) { - return; - } + File protoPath = isProtoFile ? path : new File(path.getAbsolutePath() + ".pb"); - Optional<ParsedTombstone> parsedTombstone = handleProtoTombstone(path, true); + Optional<TombstoneFile> parsedTombstone = handleProtoTombstone(protoPath, isProtoFile); if (parsedTombstone.isPresent()) { - BootReceiver.addTombstoneToDropBox( - mContext, path, parsedTombstone.get().getTombstone(), - parsedTombstone.get().getProcessName(), mTmpFileLock); + processName = parsedTombstone.get().getProcessName(); } + BootReceiver.addTombstoneToDropBox(mContext, path, isProtoFile, processName, mTmpFileLock); } - private Optional<ParsedTombstone> handleProtoTombstone( - File path, boolean addToList) { + private Optional<TombstoneFile> handleProtoTombstone(File path, boolean addToList) { final String filename = path.getName(); if (!filename.endsWith(".pb")) { Slog.w(TAG, "unexpected tombstone name: " + path); @@ -171,7 +169,7 @@ public final class NativeTombstoneManager { return Optional.empty(); } - final Optional<ParsedTombstone> parsedTombstone = TombstoneFile.parse(pfd); + final Optional<TombstoneFile> parsedTombstone = TombstoneFile.parse(pfd); if (!parsedTombstone.isPresent()) { IoUtils.closeQuietly(pfd); return Optional.empty(); @@ -184,7 +182,7 @@ public final class NativeTombstoneManager { previous.dispose(); } - mTombstones.put(number, parsedTombstone.get().getTombstoneFile()); + mTombstones.put(number, parsedTombstone.get()); } } @@ -332,27 +330,6 @@ public final class NativeTombstoneManager { } } - static class ParsedTombstone { - TombstoneFile mTombstoneFile; - Tombstone mTombstone; - ParsedTombstone(TombstoneFile tombstoneFile, Tombstone tombstone) { - mTombstoneFile = tombstoneFile; - mTombstone = tombstone; - } - - public String getProcessName() { - return mTombstoneFile.getProcessName(); - } - - public TombstoneFile getTombstoneFile() { - return mTombstoneFile; - } - - public Tombstone getTombstone() { - return mTombstone; - } - } - static class TombstoneFile { final ParcelFileDescriptor mPfd; @@ -435,21 +412,67 @@ public final class NativeTombstoneManager { } } - static Optional<ParsedTombstone> parse(ParcelFileDescriptor pfd) { - Tombstone tombstoneProto; - try (FileInputStream is = new FileInputStream(pfd.getFileDescriptor())) { - final byte[] tombstoneBytes = is.readAllBytes(); + static Optional<TombstoneFile> parse(ParcelFileDescriptor pfd) { + final FileInputStream is = new FileInputStream(pfd.getFileDescriptor()); + final ProtoInputStream stream = new ProtoInputStream(is); + + int pid = 0; + int uid = 0; + String processName = null; + String crashReason = ""; + String selinuxLabel = ""; + + try { + while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (stream.getFieldNumber()) { + case (int) Tombstone.PID: + pid = stream.readInt(Tombstone.PID); + break; + + case (int) Tombstone.UID: + uid = stream.readInt(Tombstone.UID); + break; + + case (int) Tombstone.COMMAND_LINE: + if (processName == null) { + processName = stream.readString(Tombstone.COMMAND_LINE); + } + break; - tombstoneProto = Tombstone.parseFrom( - CodedInputStream.newInstance(tombstoneBytes)); - } catch (IOException ex) { + case (int) Tombstone.CAUSES: + if (!crashReason.equals("")) { + // Causes appear in decreasing order of likelihood. For now we only + // want the most likely crash reason here, so ignore all others. + break; + } + long token = stream.start(Tombstone.CAUSES); + cause: + while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (stream.getFieldNumber()) { + case (int) Cause.HUMAN_READABLE: + crashReason = stream.readString(Cause.HUMAN_READABLE); + break cause; + + default: + break; + } + } + stream.end(token); + break; + + case (int) Tombstone.SELINUX_LABEL: + selinuxLabel = stream.readString(Tombstone.SELINUX_LABEL); + break; + + default: + break; + } + } + } catch (IOException | ProtoParseException ex) { Slog.e(TAG, "Failed to parse tombstone", ex); return Optional.empty(); } - int pid = tombstoneProto.getPid(); - int uid = tombstoneProto.getUid(); - if (!UserHandle.isApp(uid)) { Slog.e(TAG, "Tombstone's UID (" + uid + ") not an app, ignoring"); return Optional.empty(); @@ -466,7 +489,6 @@ public final class NativeTombstoneManager { final int userId = UserHandle.getUserId(uid); final int appId = UserHandle.getAppId(uid); - String selinuxLabel = tombstoneProto.getSelinuxLabel(); if (!selinuxLabel.startsWith("u:r:untrusted_app")) { Slog.e(TAG, "Tombstone has invalid selinux label (" + selinuxLabel + "), ignoring"); return Optional.empty(); @@ -478,30 +500,11 @@ public final class NativeTombstoneManager { result.mAppId = appId; result.mPid = pid; result.mUid = uid; - result.mProcessName = getCmdLineProcessName(tombstoneProto); + result.mProcessName = processName == null ? "" : processName; result.mTimestampMs = timestampMs; - result.mCrashReason = getCrashReason(tombstoneProto); + result.mCrashReason = crashReason; - return Optional.of(new ParsedTombstone(result, tombstoneProto)); - } - - private static String getCmdLineProcessName(Tombstone tombstoneProto) { - for (String cmdline : tombstoneProto.getCommandLineList()) { - if (cmdline != null) { - return cmdline; - } - } - return ""; - } - - private static String getCrashReason(Tombstone tombstoneProto) { - for (Cause cause : tombstoneProto.getCausesList()) { - if (cause.getHumanReadable() != null - && !cause.getHumanReadable().equals("")) { - return cause.getHumanReadable(); - } - } - return ""; + return Optional.of(result); } public IParcelFileDescriptorRetriever getPfdRetriever() { diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index ed9445c26740..ba8a76c9ddde 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -44,6 +44,9 @@ import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricSourceType; +import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -157,6 +160,8 @@ public class TrustManagerService extends SystemService { private final LockPatternUtils mLockPatternUtils; private final UserManager mUserManager; private final ActivityManager mActivityManager; + private FingerprintManager mFingerprintManager; + private FaceManager mFaceManager; private VirtualDeviceManagerInternal mVirtualDeviceManager; private enum TrustState { @@ -294,6 +299,8 @@ public class TrustManagerService extends SystemService { mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); mReceiver.register(mContext); mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker); + mFingerprintManager = mContext.getSystemService(FingerprintManager.class); + mFaceManager = mContext.getSystemService(FaceManager.class); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { mTrustAgentsCanRun = true; refreshAgentList(UserHandle.USER_ALL); @@ -895,7 +902,19 @@ public class TrustManagerService extends SystemService { private void notifyKeystoreOfDeviceLockState(int userId, boolean isLocked) { if (isLocked) { - Authorization.onDeviceLocked(userId, getBiometricSids(userId)); + if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) { + // A profile with unified challenge is unlockable not by its own biometrics and + // trust agents, but rather by those of the parent user. Therefore, when protecting + // the profile's UnlockedDeviceRequired keys, we must use the parent's list of + // biometric SIDs and weak unlock methods, not the profile's. + int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId) + ? resolveProfileParent(userId) : userId; + + Authorization.onDeviceLocked(userId, getBiometricSids(authUserId), + isWeakUnlockMethodEnabled(authUserId)); + } else { + Authorization.onDeviceLocked(userId, getBiometricSids(userId), false); + } } else { // Notify Keystore that the device is now unlocked for the user. Note that for unlocks // with LSKF, this is redundant with the call from LockSettingsService which provides @@ -1442,16 +1461,59 @@ public class TrustManagerService extends SystemService { if (biometricManager == null) { return new long[0]; } - if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2() - && mLockPatternUtils.isProfileWithUnifiedChallenge(userId)) { - // Profiles with unified challenge have their own set of biometrics, but the device - // unlock happens via the parent user. In this case Keystore needs to be given the list - // of biometric SIDs from the parent user, not the profile. - userId = resolveProfileParent(userId); - } return biometricManager.getAuthenticatorIds(userId); } + // Returns whether the device can become unlocked for the specified user via one of that user's + // non-strong biometrics or trust agents. This assumes that the device is currently locked, or + // is becoming locked, for the user. + private boolean isWeakUnlockMethodEnabled(int userId) { + + // Check whether the system currently allows the use of non-strong biometrics for the user, + // *and* the user actually has a non-strong biometric enrolled. + // + // The biometrics framework ostensibly supports multiple sensors per modality. However, + // that feature is unused and untested. So, we simply consider one sensor per modality. + // + // Also, currently we just consider fingerprint and face, matching Keyguard. If Keyguard + // starts supporting other biometric modalities, this will need to be updated. + if (mStrongAuthTracker.isBiometricAllowedForUser(/* isStrongBiometric= */ false, userId)) { + DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager(); + int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userId); + + if (mFingerprintManager != null + && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) == 0 + && mFingerprintManager.hasEnrolledTemplates(userId) + && isWeakOrConvenienceSensor( + mFingerprintManager.getSensorProperties().get(0))) { + Slog.i(TAG, "User is unlockable by non-strong fingerprint auth"); + return true; + } + + if (mFaceManager != null + && (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_FACE) == 0 + && mFaceManager.hasEnrolledTemplates(userId) + && isWeakOrConvenienceSensor(mFaceManager.getSensorProperties().get(0))) { + Slog.i(TAG, "User is unlockable by non-strong face auth"); + return true; + } + } + + // Check whether it's possible for the device to be actively unlocked by a trust agent. + if (getUserTrustStateInner(userId) == TrustState.TRUSTABLE + || (isAutomotive() && isTrustUsuallyManagedInternal(userId))) { + Slog.i(TAG, "User is unlockable by trust agent"); + return true; + } + + return false; + } + + private static boolean isWeakOrConvenienceSensor(SensorProperties sensor) { + return sensor.getSensorStrength() == SensorProperties.STRENGTH_WEAK + || sensor.getSensorStrength() == SensorProperties.STRENGTH_CONVENIENCE; + } + // User lifecycle @Override diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 591a55972b81..8cd55c7dd506 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -37,7 +37,6 @@ cc_library_static { "com_android_server_adb_AdbDebuggingManager.cpp", "com_android_server_am_BatteryStatsService.cpp", "com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp", - "com_android_server_BootReceiver.cpp", "com_android_server_ConsumerIrService.cpp", "com_android_server_companion_virtual_InputController.cpp", "com_android_server_devicepolicy_CryptoTestHelper.cpp", @@ -92,16 +91,6 @@ cc_library_static { header_libs: [ "bionic_libc_platform_headers", ], - - static_libs: [ - "libunwindstack", - ], - - whole_static_libs: [ - "libdebuggerd_tombstone_proto_to_text", - ], - - runtime_libs: ["libdexfile"], } cc_defaults { diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS index 33d3686ee9ce..d4f6312d19d9 100644 --- a/services/core/jni/OWNERS +++ b/services/core/jni/OWNERS @@ -32,7 +32,3 @@ per-file com_android_server_companion_virtual_InputController.cpp = file:/servic # Bug component : 158088 = per-file *AnrTimer* per-file *AnrTimer* = file:/PERFORMANCE_OWNERS - -# Bug component : 158088 = per-file com_android_server_utils_AnrTimer*.java -per-file com_android_server_utils_AnrTimer*.java = file:/PERFORMANCE_OWNERS -per-file com_android_server_BootReceiver.cpp = file:/STABILITY_OWNERS diff --git a/services/core/jni/com_android_server_BootReceiver.cpp b/services/core/jni/com_android_server_BootReceiver.cpp deleted file mode 100644 index 3892d284dafb..000000000000 --- a/services/core/jni/com_android_server_BootReceiver.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2023 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. - */ - -#include <libdebuggerd/tombstone.h> -#include <nativehelper/JNIHelp.h> - -#include <sstream> - -#include "jni.h" -#include "tombstone.pb.h" - -namespace android { - -static void writeToString(std::stringstream& ss, const std::string& line, bool should_log) { - ss << line << std::endl; -} - -static jstring com_android_server_BootReceiver_getTombstoneText(JNIEnv* env, jobject, - jbyteArray tombstoneBytes) { - Tombstone tombstone; - tombstone.ParseFromArray(env->GetByteArrayElements(tombstoneBytes, 0), - env->GetArrayLength(tombstoneBytes)); - - std::stringstream tombstoneString; - - tombstone_proto_to_text(tombstone, - std::bind(&writeToString, std::ref(tombstoneString), - std::placeholders::_1, std::placeholders::_2)); - - return env->NewStringUTF(tombstoneString.str().c_str()); -} - -static const JNINativeMethod sMethods[] = { - /* name, signature, funcPtr */ - {"getTombstoneText", "([B)Ljava/lang/String;", - (jstring*)com_android_server_BootReceiver_getTombstoneText}, -}; - -int register_com_android_server_BootReceiver(JNIEnv* env) { - return jniRegisterNativeMethods(env, "com/android/server/BootReceiver", sMethods, - NELEM(sMethods)); -} - -} // namespace android diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index e7de081bd5f8..a87902fe03c5 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -63,7 +63,6 @@ int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env); int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env); int register_android_server_companion_virtual_InputController(JNIEnv* env); int register_android_server_app_GameManagerService(JNIEnv* env); -int register_com_android_server_BootReceiver(JNIEnv* env); int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env); int register_com_android_server_display_DisplayControl(JNIEnv* env); int register_com_android_server_SystemClockTime(JNIEnv* env); @@ -123,7 +122,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_sensor_SensorService(vm, env); register_android_server_companion_virtual_InputController(env); register_android_server_app_GameManagerService(env); - register_com_android_server_BootReceiver(env); register_com_android_server_wm_TaskFpsCallbackController(env); register_com_android_server_display_DisplayControl(env); register_com_android_server_SystemClockTime(env); diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java index 37ca09d9fa27..b41568298dbc 100644 --- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java @@ -47,6 +47,10 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorProperties; +import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -69,6 +73,7 @@ import android.view.WindowManagerGlobal; import androidx.test.core.app.ApplicationProvider; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker; import com.android.modules.utils.testing.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.SystemService; @@ -105,6 +110,8 @@ public class TrustManagerServiceTest { private static final String URI_SCHEME_PACKAGE = "package"; private static final int TEST_USER_ID = 50; + private static final UserInfo TEST_USER = + new UserInfo(TEST_USER_ID, "user", UserInfo.FLAG_FULL); private static final int PARENT_USER_ID = 60; private static final int PROFILE_USER_ID = 70; private static final long[] PARENT_BIOMETRIC_SIDS = new long[] { 600L, 601L }; @@ -117,6 +124,8 @@ public class TrustManagerServiceTest { private @Mock ActivityManager mActivityManager; private @Mock BiometricManager mBiometricManager; private @Mock DevicePolicyManager mDevicePolicyManager; + private @Mock FaceManager mFaceManager; + private @Mock FingerprintManager mFingerprintManager; private @Mock IKeystoreAuthorization mKeystoreAuthorization; private @Mock LockPatternUtils mLockPatternUtils; private @Mock PackageManager mPackageManager; @@ -133,6 +142,9 @@ public class TrustManagerServiceTest { when(mActivityManager.isUserRunning(TEST_USER_ID)).thenReturn(true); doReturn(mock(IActivityManager.class)).when(() -> ActivityManager.getService()); + when(mFaceManager.getSensorProperties()).thenReturn(List.of()); + when(mFingerprintManager.getSensorProperties()).thenReturn(List.of()); + doReturn(mKeystoreAuthorization).when(() -> Authorization.getService()); when(mLockPatternUtils.getDevicePolicyManager()).thenReturn(mDevicePolicyManager); @@ -161,13 +173,16 @@ public class TrustManagerServiceTest { when(mPackageManager.checkPermission(any(), any())).thenReturn( PackageManager.PERMISSION_GRANTED); - when(mUserManager.getAliveUsers()).thenReturn( - List.of(new UserInfo(TEST_USER_ID, "user", UserInfo.FLAG_FULL))); + when(mUserManager.getAliveUsers()).thenReturn(List.of(TEST_USER)); + when(mUserManager.getEnabledProfileIds(TEST_USER_ID)).thenReturn(new int[0]); + when(mUserManager.getUserInfo(TEST_USER_ID)).thenReturn(TEST_USER); when(mWindowManager.isKeyguardLocked()).thenReturn(true); mMockContext.addMockSystemService(ActivityManager.class, mActivityManager); mMockContext.addMockSystemService(BiometricManager.class, mBiometricManager); + mMockContext.addMockSystemService(FaceManager.class, mFaceManager); + mMockContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); mMockContext.setMockPackageManager(mPackageManager); mMockContext.addMockSystemService(UserManager.class, mUserManager); doReturn(mWindowManager).when(() -> WindowManagerGlobal.getWindowManagerService()); @@ -362,9 +377,9 @@ public class TrustManagerServiceTest { when(mWindowManager.isKeyguardLocked()).thenReturn(true); mTrustManager.reportKeyguardShowingChanged(); verify(mKeystoreAuthorization) - .onDeviceLocked(eq(PARENT_USER_ID), eq(PARENT_BIOMETRIC_SIDS)); + .onDeviceLocked(eq(PARENT_USER_ID), eq(PARENT_BIOMETRIC_SIDS), eq(false)); verify(mKeystoreAuthorization) - .onDeviceLocked(eq(PROFILE_USER_ID), eq(PARENT_BIOMETRIC_SIDS)); + .onDeviceLocked(eq(PROFILE_USER_ID), eq(PARENT_BIOMETRIC_SIDS), eq(false)); } // Tests that when the device is locked for a managed profile with a *separate* challenge, the @@ -381,7 +396,188 @@ public class TrustManagerServiceTest { mTrustManager.setDeviceLockedForUser(PROFILE_USER_ID, true); verify(mKeystoreAuthorization) - .onDeviceLocked(eq(PROFILE_USER_ID), eq(PROFILE_BIOMETRIC_SIDS)); + .onDeviceLocked(eq(PROFILE_USER_ID), eq(PROFILE_BIOMETRIC_SIDS), eq(false)); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockEnabled_whenWeakFingerprintIsSetupAndAllowed() + throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFingerprint(SensorProperties.STRENGTH_WEAK); + verifyWeakUnlockEnabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockEnabled_whenWeakFaceIsSetupAndAllowed() throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFace(SensorProperties.STRENGTH_WEAK); + verifyWeakUnlockEnabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockEnabled_whenConvenienceFingerprintIsSetupAndAllowed() + throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFingerprint(SensorProperties.STRENGTH_CONVENIENCE); + verifyWeakUnlockEnabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockEnabled_whenConvenienceFaceIsSetupAndAllowed() + throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFace(SensorProperties.STRENGTH_CONVENIENCE); + verifyWeakUnlockEnabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenStrongAuthRequired() throws Exception { + setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, true); + setupFace(SensorProperties.STRENGTH_WEAK); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenNonStrongBiometricNotAllowed() throws Exception { + setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED, + /* isNonStrongBiometricAllowed= */ false); + setupFace(SensorProperties.STRENGTH_WEAK); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenWeakFingerprintSensorIsPresentButNotEnrolled() + throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFingerprint(SensorProperties.STRENGTH_WEAK, /* enrolled= */ false); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenWeakFaceSensorIsPresentButNotEnrolled() + throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFace(SensorProperties.STRENGTH_WEAK, /* enrolled= */ false); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void + testKeystoreWeakUnlockDisabled_whenWeakFingerprintIsSetupButForbiddenByDevicePolicy() + throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFingerprint(SensorProperties.STRENGTH_WEAK); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(null, TEST_USER_ID)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenWeakFaceIsSetupButForbiddenByDevicePolicy() + throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFace(SensorProperties.STRENGTH_WEAK); + when(mDevicePolicyManager.getKeyguardDisabledFeatures(null, TEST_USER_ID)) + .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FACE); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFingerprintIsSetup() throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFingerprint(SensorProperties.STRENGTH_STRONG); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFaceIsSetup() throws Exception { + setupStrongAuthTrackerToAllowEverything(); + setupFace(SensorProperties.STRENGTH_STRONG); + verifyWeakUnlockDisabled(); + } + + @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2) + public void testKeystoreWeakUnlockDisabled_whenNoBiometricsAreSetup() throws Exception { + setupStrongAuthTrackerToAllowEverything(); + verifyWeakUnlockDisabled(); + } + + private void setupStrongAuthTrackerToAllowEverything() throws Exception { + setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED, true); + } + + private void setupStrongAuthTracker(int strongAuthFlags, boolean isNonStrongBiometricAllowed) + throws Exception { + bootService(); + mService.onUserSwitching(null, new SystemService.TargetUser(TEST_USER)); + + ArgumentCaptor<StrongAuthTracker> strongAuthTracker = + ArgumentCaptor.forClass(StrongAuthTracker.class); + verify(mLockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture()); + strongAuthTracker.getValue().getStub().onStrongAuthRequiredChanged( + strongAuthFlags, TEST_USER_ID); + strongAuthTracker.getValue().getStub().onIsNonStrongBiometricAllowedChanged( + isNonStrongBiometricAllowed, TEST_USER_ID); + mService.waitForIdle(); + } + + private void setupFingerprint(int strength) { + setupFingerprint(strength, /* enrolled= */ true); + } + + private void setupFingerprint(int strength, boolean enrolled) { + int sensorId = 100; + List<SensorProperties.ComponentInfo> componentInfo = List.of(); + SensorProperties sensor = new SensorProperties(sensorId, strength, componentInfo); + when(mFingerprintManager.getSensorProperties()).thenReturn(List.of(sensor)); + when(mFingerprintManager.hasEnrolledTemplates(TEST_USER_ID)).thenReturn(enrolled); + } + + private void setupFace(int strength) { + setupFace(strength, /* enrolled= */ true); + } + + private void setupFace(int strength, boolean enrolled) { + int sensorId = 100; + List<SensorProperties.ComponentInfo> componentInfo = List.of(); + FaceSensorProperties sensor = new FaceSensorProperties( + sensorId, strength, componentInfo, FaceSensorProperties.TYPE_RGB); + when(mFaceManager.getSensorProperties()).thenReturn(List.of(sensor)); + when(mFaceManager.hasEnrolledTemplates(TEST_USER_ID)).thenReturn(enrolled); + } + + private void verifyWeakUnlockEnabled() throws Exception { + verifyWeakUnlockValue(true); + } + + private void verifyWeakUnlockDisabled() throws Exception { + verifyWeakUnlockValue(false); + } + + // Simulates a device unlock and a device lock, then verifies that the expected + // weakUnlockEnabled flag was passed to Keystore's onDeviceLocked method. + private void verifyWeakUnlockValue(boolean expectedWeakUnlockEnabled) throws Exception { + when(mWindowManager.isKeyguardLocked()).thenReturn(false); + mTrustManager.reportKeyguardShowingChanged(); + verify(mKeystoreAuthorization).onDeviceUnlocked(TEST_USER_ID, null); + + when(mWindowManager.isKeyguardLocked()).thenReturn(true); + mTrustManager.reportKeyguardShowingChanged(); + verify(mKeystoreAuthorization).onDeviceLocked(eq(TEST_USER_ID), any(), + eq(expectedWeakUnlockEnabled)); } private void setupMocksForProfile(boolean unifiedChallenge) { diff --git a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java b/services/tests/servicestests/src/com/android/server/BootReceiverTest.java deleted file mode 100644 index 523c5c060cf5..000000000000 --- a/services/tests/servicestests/src/com/android/server/BootReceiverTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import static com.google.common.truth.Truth.assertThat; - -import android.test.AndroidTestCase; - -import com.android.server.os.TombstoneProtos; -import com.android.server.os.TombstoneProtos.Tombstone; - -public class BootReceiverTest extends AndroidTestCase { - private static final String TAG = "BootReceiverTest"; - - public void testRemoveMemoryFromTombstone() { - Tombstone tombstoneBase = Tombstone.newBuilder() - .setBuildFingerprint("build_fingerprint") - .setRevision("revision") - .setPid(123) - .setTid(23) - .setUid(34) - .setSelinuxLabel("selinux_label") - .addCommandLine("cmd1") - .addCommandLine("cmd2") - .addCommandLine("cmd3") - .setProcessUptime(300) - .setAbortMessage("abort") - .addCauses(TombstoneProtos.Cause.newBuilder() - .setHumanReadable("cause1") - .setMemoryError(TombstoneProtos.MemoryError.newBuilder() - .setTool(TombstoneProtos.MemoryError.Tool.SCUDO) - .setType(TombstoneProtos.MemoryError.Type.DOUBLE_FREE))) - .addLogBuffers(TombstoneProtos.LogBuffer.newBuilder().setName("name").addLogs( - TombstoneProtos.LogMessage.newBuilder() - .setTimestamp("123") - .setMessage("message"))) - .addOpenFds(TombstoneProtos.FD.newBuilder().setFd(1).setPath("path")) - .build(); - - Tombstone tombstoneWithoutMemory = tombstoneBase.toBuilder() - .putThreads(1, TombstoneProtos.Thread.newBuilder() - .setId(1) - .setName("thread1") - .addRegisters(TombstoneProtos.Register.newBuilder().setName("r1").setU64(1)) - .addRegisters(TombstoneProtos.Register.newBuilder().setName("r2").setU64(2)) - .addBacktraceNote("backtracenote1") - .addUnreadableElfFiles("files1") - .setTaggedAddrCtrl(1) - .setPacEnabledKeys(10) - .build()) - .build(); - - Tombstone tombstoneWithMemory = tombstoneBase.toBuilder() - .addMemoryMappings(TombstoneProtos.MemoryMapping.newBuilder() - .setBeginAddress(1) - .setEndAddress(100) - .setOffset(10) - .setRead(true) - .setWrite(true) - .setExecute(false) - .setMappingName("mapping") - .setBuildId("build") - .setLoadBias(70)) - .putThreads(1, TombstoneProtos.Thread.newBuilder() - .setId(1) - .setName("thread1") - .addRegisters(TombstoneProtos.Register.newBuilder().setName("r1").setU64(1)) - .addRegisters(TombstoneProtos.Register.newBuilder().setName("r2").setU64(2)) - .addBacktraceNote("backtracenote1") - .addUnreadableElfFiles("files1") - .addMemoryDump(TombstoneProtos.MemoryDump.newBuilder() - .setRegisterName("register1") - .setMappingName("mapping") - .setBeginAddress(10)) - .setTaggedAddrCtrl(1) - .setPacEnabledKeys(10) - .build()) - .build(); - - assertThat(BootReceiver.removeMemoryFromTombstone(tombstoneWithMemory)) - .isEqualTo(tombstoneWithoutMemory); - } -} diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java index 336bfdd0fb14..a8fd6f29f862 100644 --- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java @@ -35,11 +35,13 @@ import android.util.Slog; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.Keep; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.RingBuffer; import com.android.server.usage.BroadcastResponseStatsTracker.NotificationEventType; +import java.util.function.IntFunction; +import java.util.function.Supplier; + public class BroadcastResponseStatsLogger { private static final int MAX_LOG_SIZE = @@ -49,10 +51,10 @@ public class BroadcastResponseStatsLogger { @GuardedBy("mLock") private final LogBuffer mBroadcastEventsBuffer = new LogBuffer( - BroadcastEvent.class, MAX_LOG_SIZE); + BroadcastEvent::new, BroadcastEvent[]::new, MAX_LOG_SIZE); @GuardedBy("mLock") private final LogBuffer mNotificationEventsBuffer = new LogBuffer( - NotificationEvent.class, MAX_LOG_SIZE); + NotificationEvent::new, NotificationEvent[]::new, MAX_LOG_SIZE); void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, UserHandle targetUser, long idForResponseEvent, @@ -96,8 +98,8 @@ public class BroadcastResponseStatsLogger { private static final class LogBuffer<T extends Data> extends RingBuffer<T> { - LogBuffer(Class<T> classType, int capacity) { - super(classType, capacity); + LogBuffer(Supplier<T> newItem, IntFunction<T[]> newBacking, int capacity) { + super(newItem, newBacking, capacity); } void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, @@ -179,8 +181,7 @@ public class BroadcastResponseStatsLogger { } } - @Keep - public static final class BroadcastEvent implements Data { + private static final class BroadcastEvent implements Data { public int sourceUid; public int targetUserId; public int targetUidProcessState; @@ -200,8 +201,7 @@ public class BroadcastResponseStatsLogger { } } - @Keep - public static final class NotificationEvent implements Data { + private static final class NotificationEvent implements Data { public int type; public String packageName; public int userId; @@ -218,7 +218,7 @@ public class BroadcastResponseStatsLogger { } } - public interface Data { + private interface Data { void reset(); } } diff --git a/test-base/Android.bp b/test-base/Android.bp index 527159a78ebf..70a95400bd9e 100644 --- a/test-base/Android.bp +++ b/test-base/Android.bp @@ -120,12 +120,13 @@ filegroup { path: "src", } -// Make the current.txt available for use by the cts/tests/signature tests. +// Make the current.txt available for use by the cts/tests/signature and /vendor tests. // ======================================================================== filegroup { name: "android-test-base-current.txt", visibility: [ "//cts/tests/signature/api", + "//vendor:__subpackages__", ], srcs: [ "api/current.txt", diff --git a/test-mock/Android.bp b/test-mock/Android.bp index 22320fd53631..7c4d12e338a5 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -54,12 +54,13 @@ java_sdk_library { dist_group: "android", } -// Make the current.txt available for use by the cts/tests/signature tests. +// Make the current.txt available for use by the cts/tests/signature and /vendor tests. // ======================================================================== filegroup { name: "android-test-mock-current.txt", visibility: [ "//cts/tests/signature/api", + "//vendor:__subpackages__", ], srcs: [ "api/current.txt", diff --git a/test-runner/Android.bp b/test-runner/Android.bp index 13a5dac9eb38..21e09d3221ce 100644 --- a/test-runner/Android.bp +++ b/test-runner/Android.bp @@ -79,12 +79,13 @@ java_library { ], } -// Make the current.txt available for use by the cts/tests/signature tests. +// Make the current.txt available for use by the cts/tests/signature and /vendor tests. // ======================================================================== filegroup { name: "android-test-runner-current.txt", visibility: [ "//cts/tests/signature/api", + "//vendor:__subpackages__", ], srcs: [ "api/current.txt", |