diff options
30 files changed, 577 insertions, 291 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 4ddb546a351e..d932a29beca6 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2849,14 +2849,14 @@ public class AppOpsManager { private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>(); /** - * If a thread is currently executing a two-way binder transaction, this stores the - * ops that were noted blaming any app (the caller, the caller of the caller, etc). + * If a thread is currently executing a two-way binder transaction, this stores the op-codes of + * the app-ops that were noted during this transaction. * * @see #getNotedOpCollectionMode * @see #collectNotedOpSync */ - private static final ThreadLocal<ArrayMap<String, ArrayMap<String, long[]>>> - sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>(); + private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction = + new ThreadLocal<>(); /** Whether noting for an appop should be collected */ private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP]; @@ -7205,6 +7205,34 @@ public class AppOpsManager { * @hide */ public interface OnOpStartedListener { + + /** + * Represents a start operation that was unsuccessful + * @hide + */ + public int START_TYPE_FAILED = 0; + + /** + * Represents a successful start operation + * @hide + */ + public int START_TYPE_STARTED = 1; + + /** + * Represents an operation where a restricted operation became unrestricted, and resumed. + * @hide + */ + public int START_TYPE_RESUMED = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = { "TYPE_" }, value = { + START_TYPE_FAILED, + START_TYPE_STARTED, + START_TYPE_RESUMED + }) + public @interface StartedType {} + /** * Called when an op was started. * @@ -7213,11 +7241,35 @@ public class AppOpsManager { * @param uid The UID performing the operation. * @param packageName The package performing the operation. * @param attributionTag The attribution tag performing the operation. - * @param flags The flags of this op + * @param flags The flags of this op. * @param result The result of the start. */ void onOpStarted(int op, int uid, String packageName, String attributionTag, @OpFlags int flags, @Mode int result); + + /** + * Called when an op was started. + * + * Note: This is only for op starts. It is not called when an op is noted or stopped. + * By default, unless this method is overridden, no code will be executed for resume + * events. + * @param op The op code. + * @param uid The UID performing the operation. + * @param packageName The package performing the operation. + * @param attributionTag The attribution tag performing the operation. + * @param flags The flags of this op. + * @param result The result of the start. + * @param startType The start type of this start event. Either failed, resumed, or started. + * @param attributionFlags The location of this started op in an attribution chain. + * @param attributionChainId The ID of the attribution chain of this op, if it is in one. + */ + default void onOpStarted(int op, int uid, String packageName, String attributionTag, + @OpFlags int flags, @Mode int result, @StartedType int startType, + @AttributionFlags int attributionFlags, int attributionChainId) { + if (startType != START_TYPE_RESUMED) { + onOpStarted(op, uid, packageName, attributionTag, flags, result); + } + } } AppOpsManager(Context context, IAppOpsService service) { @@ -7858,8 +7910,10 @@ public class AppOpsManager { cb = new IAppOpsStartedCallback.Stub() { @Override public void opStarted(int op, int uid, String packageName, String attributionTag, - int flags, int mode) { - callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode); + int flags, int mode, int startType, int attributionFlags, + int attributionChainId) { + callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode, + startType, attributionFlags, attributionChainId); } }; mStartedWatchers.put(callback, cb); @@ -9052,6 +9106,66 @@ public class AppOpsManager { } /** + * State of a temporarily paused noted app-ops collection. + * + * @see #pauseNotedAppOpsCollection() + * + * @hide + */ + public static class PausedNotedAppOpsCollection { + final int mUid; + final @Nullable ArrayMap<String, long[]> mCollectedNotedAppOps; + + PausedNotedAppOpsCollection(int uid, @Nullable ArrayMap<String, + long[]> collectedNotedAppOps) { + mUid = uid; + mCollectedNotedAppOps = collectedNotedAppOps; + } + } + + /** + * Temporarily suspend collection of noted app-ops when binder-thread calls into the other + * process. During such a call there might be call-backs coming back on the same thread which + * should not be accounted to the current collection. + * + * @return a state needed to resume the collection + * + * @hide + */ + public static @Nullable PausedNotedAppOpsCollection pauseNotedAppOpsCollection() { + Integer previousUid = sBinderThreadCallingUid.get(); + if (previousUid != null) { + ArrayMap<String, long[]> previousCollectedNotedAppOps = + sAppOpsNotedInThisBinderTransaction.get(); + + sBinderThreadCallingUid.remove(); + sAppOpsNotedInThisBinderTransaction.remove(); + + return new PausedNotedAppOpsCollection(previousUid, previousCollectedNotedAppOps); + } + + return null; + } + + /** + * Resume a collection paused via {@link #pauseNotedAppOpsCollection}. + * + * @param prevCollection The state of the previous collection + * + * @hide + */ + public static void resumeNotedAppOpsCollection( + @Nullable PausedNotedAppOpsCollection prevCollection) { + if (prevCollection != null) { + sBinderThreadCallingUid.set(prevCollection.mUid); + + if (prevCollection.mCollectedNotedAppOps != null) { + sAppOpsNotedInThisBinderTransaction.set(prevCollection.mCollectedNotedAppOps); + } + } + } + + /** * Finish collection of noted appops on this thread. * * <p>Called at the end of a two way binder transaction. @@ -9091,47 +9205,26 @@ public class AppOpsManager { */ @TestApi public static void collectNotedOpSync(@NonNull SyncNotedAppOp syncOp) { - collectNotedOpSync(sOpStrToOp.get(syncOp.getOp()), syncOp.getAttributionTag(), - syncOp.getPackageName()); - } - - /** - * Collect a noted op when inside of a two-way binder call. - * - * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded} - * - * @param code the op code to note for - * @param attributionTag the attribution tag to note for - * @param packageName the package to note for - */ - private static void collectNotedOpSync(int code, @Nullable String attributionTag, - @NonNull String packageName) { // If this is inside of a two-way binder call: // We are inside of a two-way binder call. Delivered to caller via // {@link #prefixParcelWithAppOpsIfNeeded} - ArrayMap<String, ArrayMap<String, long[]>> appOpsNoted = - sAppOpsNotedInThisBinderTransaction.get(); + int op = sOpStrToOp.get(syncOp.getOp()); + ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get(); if (appOpsNoted == null) { appOpsNoted = new ArrayMap<>(1); sAppOpsNotedInThisBinderTransaction.set(appOpsNoted); } - ArrayMap<String, long[]> packageAppOpsNotedForAttribution = appOpsNoted.get(packageName); - if (packageAppOpsNotedForAttribution == null) { - packageAppOpsNotedForAttribution = new ArrayMap<>(1); - appOpsNoted.put(packageName, packageAppOpsNotedForAttribution); - } - - long[] appOpsNotedForAttribution = packageAppOpsNotedForAttribution.get(attributionTag); + long[] appOpsNotedForAttribution = appOpsNoted.get(syncOp.getAttributionTag()); if (appOpsNotedForAttribution == null) { appOpsNotedForAttribution = new long[2]; - packageAppOpsNotedForAttribution.put(attributionTag, appOpsNotedForAttribution); + appOpsNoted.put(syncOp.getAttributionTag(), appOpsNotedForAttribution); } - if (code < 64) { - appOpsNotedForAttribution[0] |= 1L << code; + if (op < 64) { + appOpsNotedForAttribution[0] |= 1L << op; } else { - appOpsNotedForAttribution[1] |= 1L << (code - 64); + appOpsNotedForAttribution[1] |= 1L << (op - 64); } } @@ -9185,7 +9278,9 @@ public class AppOpsManager { } } - if (isListeningForOpNotedInBinderTransaction()) { + Integer binderUid = sBinderThreadCallingUid.get(); + + if (binderUid != null && binderUid == uid) { return COLLECT_SYNC; } else { return COLLECT_ASYNC; @@ -9204,32 +9299,20 @@ public class AppOpsManager { */ // TODO (b/186872903) Refactor how sync noted ops are propagated. public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) { - if (!isListeningForOpNotedInBinderTransaction()) { - return; - } - final ArrayMap<String, ArrayMap<String, long[]>> notedAppOps = - sAppOpsNotedInThisBinderTransaction.get(); + ArrayMap<String, long[]> notedAppOps = sAppOpsNotedInThisBinderTransaction.get(); if (notedAppOps == null) { return; } p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER); - final int packageCount = notedAppOps.size(); - p.writeInt(packageCount); + int numAttributionWithNotesAppOps = notedAppOps.size(); + p.writeInt(numAttributionWithNotesAppOps); - for (int i = 0; i < packageCount; i++) { + for (int i = 0; i < numAttributionWithNotesAppOps; i++) { p.writeString(notedAppOps.keyAt(i)); - - final ArrayMap<String, long[]> notedTagAppOps = notedAppOps.valueAt(i); - final int tagCount = notedTagAppOps.size(); - p.writeInt(tagCount); - - for (int j = 0; j < tagCount; j++) { - p.writeString(notedTagAppOps.keyAt(j)); - p.writeLong(notedTagAppOps.valueAt(j)[0]); - p.writeLong(notedTagAppOps.valueAt(j)[1]); - } + p.writeLong(notedAppOps.valueAt(i)[0]); + p.writeLong(notedAppOps.valueAt(i)[1]); } } @@ -9244,55 +9327,37 @@ public class AppOpsManager { * @hide */ public static void readAndLogNotedAppops(@NonNull Parcel p) { - final int packageCount = p.readInt(); - if (packageCount <= 0) { - return; - } + int numAttributionsWithNotedAppOps = p.readInt(); - final String myPackageName = ActivityThread.currentPackageName(); + for (int i = 0; i < numAttributionsWithNotedAppOps; i++) { + String attributionTag = p.readString(); + long[] rawNotedAppOps = new long[2]; + rawNotedAppOps[0] = p.readLong(); + rawNotedAppOps[1] = p.readLong(); - synchronized (sLock) { - for (int i = 0; i < packageCount; i++) { - final String packageName = p.readString(); - - final int tagCount = p.readInt(); - for (int j = 0; j < tagCount; j++) { - final String attributionTag = p.readString(); - final long[] rawNotedAppOps = new long[2]; - rawNotedAppOps[0] = p.readLong(); - rawNotedAppOps[1] = p.readLong(); + if (rawNotedAppOps[0] != 0 || rawNotedAppOps[1] != 0) { + BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps); - if (rawNotedAppOps[0] == 0 && rawNotedAppOps[1] == 0) { - continue; - } - - final BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps); + synchronized (sLock) { for (int code = notedAppOps.nextSetBit(0); code != -1; code = notedAppOps.nextSetBit(code + 1)) { - if (Objects.equals(myPackageName, packageName)) { - if (sOnOpNotedCallback != null) { - sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, - attributionTag, packageName)); - } else { - String message = getFormattedStackTrace(); - sUnforwardedOps.add(new AsyncNotedAppOp(code, Process.myUid(), - attributionTag, message, System.currentTimeMillis())); - if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) { - sUnforwardedOps.remove(0); - } + if (sOnOpNotedCallback != null) { + sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag)); + } else { + String message = getFormattedStackTrace(); + sUnforwardedOps.add( + new AsyncNotedAppOp(code, Process.myUid(), attributionTag, + message, System.currentTimeMillis())); + if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) { + sUnforwardedOps.remove(0); } - } else if (isListeningForOpNotedInBinderTransaction()) { - collectNotedOpSync(code, attributionTag, packageName); - } - } - for (int code = notedAppOps.nextSetBit(0); code != -1; - code = notedAppOps.nextSetBit(code + 1)) { - if (Objects.equals(myPackageName, packageName)) { - sMessageCollector.onNoted(new SyncNotedAppOp(code, - attributionTag, packageName)); } } } + for (int code = notedAppOps.nextSetBit(0); code != -1; + code = notedAppOps.nextSetBit(code + 1)) { + sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag)); + } } } } @@ -9398,15 +9463,7 @@ public class AppOpsManager { * @hide */ public static boolean isListeningForOpNoted() { - return sOnOpNotedCallback != null || isListeningForOpNotedInBinderTransaction() - || isCollectingStackTraces(); - } - - /** - * @return whether we are in a binder transaction and collecting appops. - */ - private static boolean isListeningForOpNotedInBinderTransaction() { - return sBinderThreadCallingUid.get() != null; + return sOnOpNotedCallback != null || isCollectingStackTraces(); } /** diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java index 32d889e81cb0..7c0c08a7fc35 100644 --- a/core/java/android/app/SyncNotedAppOp.java +++ b/core/java/android/app/SyncNotedAppOp.java @@ -21,7 +21,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Parcelable; -import android.os.Process; import com.android.internal.annotations.Immutable; import com.android.internal.util.DataClass; @@ -29,6 +28,8 @@ import com.android.internal.util.DataClass; /** * Description of an app-op that was noted for the current process. * + * Note: package name is currently unused in the system. + * * <p>This is either delivered after a * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or * when the app diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index d44b016cb5d0..3d466a0bf007 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -560,6 +560,9 @@ public final class BinderProxy implements IBinder { } } + final AppOpsManager.PausedNotedAppOpsCollection prevCollection = + AppOpsManager.pauseNotedAppOpsCollection(); + if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) { flags |= FLAG_COLLECT_NOTED_APP_OPS; } @@ -567,6 +570,8 @@ public final class BinderProxy implements IBinder { try { return transactNative(code, data, reply, flags); } finally { + AppOpsManager.resumeNotedAppOpsCollection(prevCollection); + if (transactListener != null) { transactListener.onTransactEnded(session); } diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java index 03f94c549512..19f204b377c8 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -31,7 +31,9 @@ import static android.app.AppOpsManager.OPSTR_FINE_LOCATION; import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA; import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE; import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO; +import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; +import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.media.AudioSystem.MODE_IN_COMMUNICATION; import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; @@ -63,7 +65,8 @@ import java.util.Objects; * * @hide */ -public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener { +public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener, + AppOpsManager.OnOpStartedListener { /** Whether to show the mic and camera icons. */ private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled"; @@ -160,9 +163,10 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis mUserContexts = new ArrayMap<>(); mUserContexts.put(Process.myUserHandle(), mContext); // TODO ntmyren: make this listen for flag enable/disable changes - String[] ops = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO }; - mContext.getSystemService(AppOpsManager.class).startWatchingActive(ops, - context.getMainExecutor(), this); + String[] opStrs = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO }; + mAppOpsManager.startWatchingActive(opStrs, context.getMainExecutor(), this); + int[] ops = { OP_CAMERA, OP_RECORD_AUDIO }; + mAppOpsManager.startWatchingStarted(ops, this); } private Context getUserContext(UserHandle user) { @@ -182,25 +186,65 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags, int attributionChainId) { - if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE - || attributionFlags == ATTRIBUTION_FLAGS_NONE - || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { - // If this is not a chain, or it is untrusted, return + if (active) { + // Started callback handles these return; } - if (!active) { - // if any link in the chain is finished, remove the chain. - // TODO ntmyren: be smarter about this - mAttributionChains.remove(attributionChainId); + // if any link in the chain is finished, remove the chain. Then, find any other chains that + // contain this op/package/uid/tag combination, and remove them, as well. + // TODO ntmyren: be smarter about this + mAttributionChains.remove(attributionChainId); + int numChains = mAttributionChains.size(); + ArrayList<Integer> toRemove = new ArrayList<>(); + for (int i = 0; i < numChains; i++) { + int chainId = mAttributionChains.keyAt(i); + ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i); + int chainSize = chain.size(); + for (int j = 0; j < chainSize; j++) { + AccessChainLink link = chain.get(j); + if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) { + toRemove.add(chainId); + break; + } + } + } + mAttributionChains.removeAll(toRemove); + } + + @Override + public void onOpStarted(int op, int uid, String packageName, String attributionTag, + @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) { + // not part of an attribution chain. Do nothing + } + + @Override + public void onOpStarted(int op, int uid, String packageName, String attributionTag, + @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result, + @StartedType int startedType, @AttributionFlags int attributionFlags, + int attributionChainId) { + if (startedType == START_TYPE_FAILED || attributionChainId == ATTRIBUTION_CHAIN_ID_NONE + || attributionFlags == ATTRIBUTION_FLAGS_NONE + || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) { + // If this is not a successful start, or it is not a chain, or it is untrusted, return return; } + addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid, + attributionTag, attributionFlags, attributionChainId); + } + + private void addLinkToChainIfNotPresent(String op, String packageName, int uid, + String attributionTag, int attributionFlags, int attributionChainId) { ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent( attributionChainId, k -> new ArrayList<>()); AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid, attributionFlags); + if (currentChain.contains(link)) { + return; + } + int currSize = currentChain.size(); if (currSize == 0 || link.isEnd() || !currentChain.get(currSize - 1).isEnd()) { // if the list is empty, this link is the end, or the last link in the current chain @@ -613,5 +657,21 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis public boolean isStart() { return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0; } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof AccessChainLink)) { + return false; + } + AccessChainLink other = (AccessChainLink) obj; + return other.flags == flags && packageAndOpEquals(other.usage.op, + other.usage.packageName, other.usage.attributionTag, other.usage.uid); + } + + public boolean packageAndOpEquals(String op, String packageName, String attributionTag, + int uid) { + return Objects.equals(op, usage.op) && Objects.equals(packageName, usage.packageName) + && Objects.equals(attributionTag, usage.attributionTag) && uid == usage.uid; + } } } diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index f21d855ddcf9..6c2d6a1c3f2e 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -1242,7 +1242,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall mBlastSurfaceControl.setTransformHint(mTransformHint); if (mBlastBufferQueue != null) { mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, - mFormat); + mFormat, transaction); } } else { transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight); diff --git a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl index 3a108e7e1d94..06640cb4ee06 100644 --- a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl +++ b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl @@ -18,5 +18,6 @@ package com.android.internal.app; // Iterface to observe op starts oneway interface IAppOpsStartedCallback { - void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode); + void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode, + int startedType, int attributionFlags, int attributionChainId); } diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp index b46b5a23e3fb..d4ae6d769cf7 100644 --- a/core/jni/android_graphics_BLASTBufferQueue.cpp +++ b/core/jni/android_graphics_BLASTBufferQueue.cpp @@ -105,9 +105,11 @@ static void nativeSetNextTransaction(JNIEnv* env, jclass clazz, jlong ptr, jlong } static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width, - jlong height, jint format) { + jlong height, jint format, jlong transactionPtr) { sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr); - queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format); + auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr); + queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format, + transaction); } static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) { @@ -144,7 +146,7 @@ static const JNINativeMethod gMethods[] = { {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface}, {"nativeDestroy", "(J)V", (void*)nativeDestroy}, {"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction}, - {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate}, + {"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate}, {"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue}, {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction}, {"nativeSetTransactionCompleteCallback", diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index 3f9cee11da36..2936a080723b 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -1949,7 +1949,7 @@ <string name="maximize_button_text" msgid="4258922519914732645">"بڑا کریں"</string> <string name="close_button_text" msgid="10603510034455258">"بند کریں"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> - <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب"</string> + <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب دیں"</string> <string name="call_notification_answer_video_action" msgid="2086030940195382249">"ویڈیو"</string> <string name="call_notification_decline_action" msgid="3700345945214000726">"مسترد کریں"</string> <string name="call_notification_hang_up_action" msgid="9130720590159188131">"منقطع کر دیں"</string> diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java index 6c1c2ee1ee57..36215ecc1403 100644 --- a/graphics/java/android/graphics/BLASTBufferQueue.java +++ b/graphics/java/android/graphics/BLASTBufferQueue.java @@ -33,7 +33,7 @@ public final class BLASTBufferQueue { private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle); private static native void nativeSetNextTransaction(long ptr, long transactionPtr); private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height, - int format); + int format, long transactionPtr); private static native void nativeFlushShadowQueue(long ptr); private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr, long frameNumber); @@ -92,9 +92,15 @@ public final class BLASTBufferQueue { * @param width The new width for the buffer. * @param height The new height for the buffer. * @param format The new format for the buffer. + * @param t Adds destination frame changes to the passed in transaction. */ + public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format, + SurfaceControl.Transaction t) { + nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, t.mNativeObject); + } + public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) { - nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format); + nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, 0); } /** diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java index 1472980efd4e..e0339dacf5ac 100644 --- a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java +++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java @@ -64,9 +64,9 @@ public class BiometricActionDisabledByAdminController extends BaseActionDisabled return (dialog, which) -> { Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component); final Intent intent = new Intent(ACTION_LEARN_MORE) - .setComponent(enforcedAdmin.component) .putExtra(EXTRA_SETTING_KEY, EXTRA_SETTING_VALUE) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .setPackage(enforcedAdmin.component.getPackageName()); context.startActivity(intent); }; } diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml index 2789ed125b09..eb7638233efd 100644 --- a/packages/SystemUI/res/layout/keyguard_status_bar.xml +++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml @@ -30,6 +30,7 @@ android:id="@+id/status_icon_area" android:layout_width="wrap_content" android:layout_height="match_parent" + android:paddingEnd="@dimen/system_icons_keyguard_padding_end" android:paddingTop="@dimen/status_bar_padding_top" android:layout_alignParentEnd="true" android:gravity="center_vertical|end" > @@ -38,12 +39,10 @@ android:layout_height="match_parent" android:layout_weight="1" android:layout_marginStart="@dimen/system_icons_super_container_margin_start" - android:gravity="center_vertical|end" - android:paddingEnd="@dimen/system_icons_keyguard_padding_end" > + android:gravity="center_vertical|end"> <include layout="@layout/system_icons" /> </FrameLayout> - <ImageView android:id="@+id/multi_user_avatar" android:layout_width="@dimen/multi_user_avatar_keyguard_size" android:layout_height="@dimen/multi_user_avatar_keyguard_size" diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 7d00c5be4d44..e17f032e961f 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -799,7 +799,7 @@ <item quantity="other">%d分</item> <item quantity="one">%d分</item> </plurals> - <string name="battery_panel_title" msgid="5931157246673665963">"電池の使用状況"</string> + <string name="battery_panel_title" msgid="5931157246673665963">"バッテリーの使用状況"</string> <string name="battery_detail_charging_summary" msgid="8821202155297559706">"充電中はバッテリー セーバーは利用できません"</string> <string name="battery_detail_switch_title" msgid="6940976502957380405">"バッテリー セーバー"</string> <string name="battery_detail_switch_summary" msgid="3668748557848025990">"パフォーマンスとバックグラウンド データを制限します"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index f62d9dac7984..8a26ed364e15 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -707,11 +707,11 @@ <string name="tuner_full_importance_settings" msgid="1388025816553459059">"Эскертмелерди башкаруу каражаттары"</string> <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Күйүк"</string> <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Өчүк"</string> - <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрсөтүлөт \n- Билдирмелер толук экранда көрсөтүлөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрсөтүлөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string> + <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрүнөт \n- Билдирмелер толук экранда көрүнөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрүнөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string> <string name="notification_header_default_channel" msgid="225454696914642444">"Билдирмелер"</string> <string name="notification_channel_disabled" msgid="928065923928416337">"Мындан ары бул билдирмелер сизге көрүнбөйт"</string> <string name="notification_channel_minimized" msgid="6892672757877552959">"Бул билдирмелер кичирейтилет"</string> - <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрсөтүлөт"</string> + <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрүнөт"</string> <string name="notification_channel_unsilenced" msgid="94878840742161152">"Бул билдирмелер тууралуу кабарлап турабыз"</string> <string name="inline_blocking_helper" msgid="2891486013649543452">"Адатта мындай билдирмелерди өткөрүп жибересиз. \nАлар көрүнө берсинби?"</string> <string name="inline_done_button" msgid="6043094985588909584">"Бүттү"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index c503ebdb368e..40ceb59e7169 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -452,8 +452,7 @@ <string name="notification_tap_again" msgid="4477318164947497249">"खोल्न पुनः ट्याप गर्नुहोस्"</string> <string name="tap_again" msgid="1315420114387908655">"फेरि ट्याप गर्नुहोस्"</string> <string name="keyguard_unlock" msgid="8031975796351361601">"खोल्न माथितिर स्वाइप गर्नुहोस्"</string> - <!-- no translation found for keyguard_unlock_press (8488350566398524740) --> - <skip /> + <string name="keyguard_unlock_press" msgid="8488350566398524740">"अनलक गर्न प्रेस गर्नुहोस्"</string> <string name="keyguard_retry" msgid="886802522584053523">"फेरि प्रयास गर्न माथितिर स्वाइप गर्नुहोस्"</string> <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string> <string name="do_disclosure_generic" msgid="4896482821974707167">"यो डिभाइस तपाईंको सङ्गठनको स्वामित्वमा छ"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 6845b5b5877d..a948fae6de6b 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -452,8 +452,7 @@ <string name="notification_tap_again" msgid="4477318164947497249">"Trokit përsëri për ta hapur"</string> <string name="tap_again" msgid="1315420114387908655">"Trokit sërish"</string> <string name="keyguard_unlock" msgid="8031975796351361601">"Rrëshqit lart për ta hapur"</string> - <!-- no translation found for keyguard_unlock_press (8488350566398524740) --> - <skip /> + <string name="keyguard_unlock_press" msgid="8488350566398524740">"Shtyp për të hapur"</string> <string name="keyguard_retry" msgid="886802522584053523">"Rrëshqit lart për të provuar përsëri"</string> <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string> <string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java index 1b4ae9ea3f32..2c810c93b2ee 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java @@ -157,15 +157,13 @@ public class StackScrollAlgorithm { // After the shelf has updated its yTranslation, explicitly set alpha=0 for view below shelf // to skip rendering them in the hardware layer. We do not set them invisible because that // runs invalidate & onDraw when these views return onscreen, which is more expensive. + if (shelf.getViewState().hidden) { + // When the shelf is hidden, it won't clip views, so we don't hide rows + return; + } final float shelfTop = shelf.getViewState().yTranslation; for (ExpandableView view : algorithmState.visibleChildren) { - if (view instanceof ExpandableNotificationRow) { - ExpandableNotificationRow row = (ExpandableNotificationRow) view; - if (row.isHeadsUp() || row.isHeadsUpAnimatingAway()) { - continue; - } - } final float viewTop = view.getViewState().yTranslation; if (viewTop >= shelfTop) { view.getViewState().alpha = 0; diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java index ecd620e78c3c..40e63dac72ea 100644 --- a/services/core/java/com/android/server/SensorPrivacyService.java +++ b/services/core/java/com/android/server/SensorPrivacyService.java @@ -21,7 +21,6 @@ import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; import static android.app.ActivityManager.RunningServiceInfo; import static android.app.ActivityManager.RunningTaskInfo; -import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_CAMERA; import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA; @@ -382,17 +381,9 @@ public final class SensorPrivacyService extends SystemService { int sensor; if (result == MODE_IGNORED) { - if (code == OP_RECORD_AUDIO) { + if (code == OP_RECORD_AUDIO || code == OP_PHONE_CALL_MICROPHONE) { sensor = MICROPHONE; - } else if (code == OP_CAMERA) { - sensor = CAMERA; - } else { - return; - } - } else if (result == MODE_ALLOWED) { - if (code == OP_PHONE_CALL_MICROPHONE) { - sensor = MICROPHONE; - } else if (code == OP_PHONE_CALL_CAMERA) { + } else if (code == OP_CAMERA || code == OP_PHONE_CALL_CAMERA) { sensor = CAMERA; } else { return; @@ -1276,10 +1267,14 @@ public final class SensorPrivacyService extends SystemService { case MICROPHONE: mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled, mAppOpsRestrictionToken); + mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled, + mAppOpsRestrictionToken); break; case CAMERA: mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled, mAppOpsRestrictionToken); + mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_CAMERA, enabled, + mAppOpsRestrictionToken); break; } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 07847f1df053..45e6f1ec4bf8 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -102,6 +102,7 @@ import android.app.usage.UsageEvents; import android.appwidget.AppWidgetManagerInternal; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; +import android.compat.annotation.Overridable; import android.content.ComponentName; import android.content.ComponentName.WithComponentName; import android.content.Context; @@ -307,6 +308,7 @@ public final class ActiveServices { */ @ChangeId @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S) + @Overridable static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L; /** diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index a9905dcf8904..64b9bd98a2fc 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -45,6 +45,9 @@ import static android.app.AppOpsManager.OP_NONE; import static android.app.AppOpsManager.OP_PLAY_AUDIO; import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD; +import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED; +import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_RESUMED; +import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED; import static android.app.AppOpsManager.OpEventProxyInfo; import static android.app.AppOpsManager.RestrictionBypass; import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING; @@ -1238,6 +1241,11 @@ public class AppOpsService extends IAppOpsService.Stub { scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName, tag, true, event.getAttributionFlags(), event.getAttributionChainId()); } + // Note: this always sends MODE_ALLOWED, even if the mode is FOREGROUND + // TODO ntmyren: figure out how to get the real mode. + scheduleOpStartedIfNeededLocked(parent.op, parent.uid, parent.packageName, + tag, event.getFlags(), MODE_ALLOWED, START_TYPE_RESUMED, + event.getAttributionFlags(), event.getAttributionChainId()); } mPausedInProgressEvents = null; } @@ -3438,7 +3446,7 @@ public class AppOpsService extends IAppOpsService.Stub { + " package " + packageName + "flags: " + AppOpsManager.flagsToString(flags)); return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag, - packageName + " flags: " + AppOpsManager.flagsToString(flags)); + packageName); } final Op op = getOpLocked(ops, code, uid, true); final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag); @@ -3945,13 +3953,15 @@ public class AppOpsService extends IAppOpsService.Stub { } boolean isRestricted = false; + int startType = START_TYPE_FAILED; synchronized (this) { final Ops ops = getOpsLocked(uid, packageName, attributionTag, pvr.isAttributionTagValid, pvr.bypass, /* edit */ true); if (ops == null) { if (!dryRun) { scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, - flags, AppOpsManager.MODE_IGNORED); + flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags, + attributionChainId); } if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + packageName + " flags: " @@ -3977,7 +3987,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (!dryRun) { attributedOp.rejected(uidState.state, flags); scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, - flags, uidMode); + flags, uidMode, startType, attributionFlags, attributionChainId); } return new SyncNotedAppOp(uidMode, code, attributionTag, packageName); } @@ -3993,7 +4003,7 @@ public class AppOpsService extends IAppOpsService.Stub { if (!dryRun) { attributedOp.rejected(uidState.state, flags); scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, - flags, mode); + flags, mode, startType, attributionFlags, attributionChainId); } return new SyncNotedAppOp(mode, code, attributionTag, packageName); } @@ -4011,12 +4021,14 @@ public class AppOpsService extends IAppOpsService.Stub { attributedOp.started(clientId, proxyUid, proxyPackageName, proxyAttributionTag, uidState.state, flags, attributionFlags, attributionChainId); + startType = START_TYPE_STARTED; } } catch (RemoteException e) { throw new RuntimeException(e); } scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags, - isRestricted ? MODE_IGNORED : MODE_ALLOWED); + isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags, + attributionChainId); } } @@ -4187,7 +4199,9 @@ public class AppOpsService extends IAppOpsService.Stub { } private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName, - String attributionTag, @OpFlags int flags, @Mode int result) { + String attributionTag, @OpFlags int flags, @Mode int result, + @AppOpsManager.OnOpStartedListener.StartedType int startedType, + @AttributionFlags int attributionFlags, int attributionChainId) { ArraySet<StartedCallback> dispatchedCallbacks = null; final int callbackListCount = mStartedWatchers.size(); for (int i = 0; i < callbackListCount; i++) { @@ -4213,12 +4227,13 @@ public class AppOpsService extends IAppOpsService.Stub { mHandler.sendMessage(PooledLambda.obtainMessage( AppOpsService::notifyOpStarted, this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags, - result)); + result, startedType, attributionFlags, attributionChainId)); } private void notifyOpStarted(ArraySet<StartedCallback> callbacks, int code, int uid, String packageName, String attributionTag, @OpFlags int flags, - @Mode int result) { + @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType, + @AttributionFlags int attributionFlags, int attributionChainId) { final long identity = Binder.clearCallingIdentity(); try { final int callbackCount = callbacks.size(); @@ -4226,7 +4241,7 @@ public class AppOpsService extends IAppOpsService.Stub { final StartedCallback callback = callbacks.valueAt(i); try { callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags, - result); + result, startedType, attributionFlags, attributionChainId); } catch (RemoteException e) { /* do nothing */ } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index f4327e8a104d..705b3aa12391 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -180,7 +180,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> + ", isBP: " + isBiometricPrompt() + ", listener: " + listener + ", requireConfirmation: " + mRequireConfirmation - + ", user: " + getTargetUserId()); + + ", user: " + getTargetUserId() + + ", clientMonitor: " + toString()); final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId()); if (isCryptoOperation()) { @@ -304,6 +305,11 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> public void handleLifecycleAfterAuth() { AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */); } + + @Override + public void sendAuthenticationCanceled() { + sendCancelOnly(listener); + } }); } else { // Allow system-defined limit of number of attempts before giving up @@ -338,10 +344,30 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> public void handleLifecycleAfterAuth() { AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */); } + + @Override + public void sendAuthenticationCanceled() { + sendCancelOnly(listener); + } }); } } + private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) { + if (listener == null) { + Slog.e(TAG, "Unable to sendAuthenticationCanceled, listener null"); + return; + } + try { + listener.onError(getSensorId(), + getCookie(), + BiometricConstants.BIOMETRIC_ERROR_CANCELED, + 0 /* vendorCode */); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + } + } + @Override public void onAcquired(int acquiredInfo, int vendorCode) { super.onAcquired(acquiredInfo, vendorCode); diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java index a15ecada3cae..6d32fdebe582 100644 --- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java +++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java @@ -73,6 +73,11 @@ public class CoexCoordinator { * from scheduler if auth was successful). */ void handleLifecycleAfterAuth(); + + /** + * Requests the owner to notify the caller that authentication was canceled. + */ + void sendAuthenticationCanceled(); } private static CoexCoordinator sInstance; @@ -356,7 +361,11 @@ public class CoexCoordinator { private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) { for (SuccessfulAuth auth : mSuccessfulAuths) { if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) { - Slog.d(TAG, "Removing stale auth: " + auth); + // TODO(b/193089985): This removes the auth but does not notify the client with + // an appropriate lifecycle event (such as ERROR_CANCELED), and violates the + // API contract. However, this might be OK for now since the validity duration + // is way longer than the time it takes to auth with fingerprint. + Slog.e(TAG, "Removing stale auth: " + auth); mSuccessfulAuths.remove(auth); } else if (auth.mSensorType == SENSOR_TYPE_FACE) { mSuccessfulAuths.remove(auth); @@ -367,9 +376,13 @@ public class CoexCoordinator { } private void removeAndFinishAllFaceFromQueue() { + // Note that these auth are all successful, but have never notified the client (e.g. + // keyguard). To comply with the authentication lifecycle, we must notify the client that + // auth is "done". The safest thing to do is to send ERROR_CANCELED. for (SuccessfulAuth auth : mSuccessfulAuths) { if (auth.mSensorType == SENSOR_TYPE_FACE) { - Slog.d(TAG, "Removing from queue and finishing: " + auth); + Slog.d(TAG, "Removing from queue, canceling, and finishing: " + auth); + auth.mCallback.sendAuthenticationCanceled(); auth.mCallback.handleLifecycleAfterAuth(); mSuccessfulAuths.remove(auth); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ee44c10edbf3..031910a81260 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -24838,11 +24838,11 @@ public class PackageManagerService extends IPackageManager.Stub pw.println("vers,1"); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_VERSION) - && packageName == null) { - // dump version information for all volumes with installed packages - dump(DumpState.DUMP_VERSION, fd, pw, dumpState); + // reader + if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) { + if (!checkin) { + dump(DumpState.DUMP_VERSION, fd, pw, dumpState); + } } if (!checkin @@ -24873,8 +24873,7 @@ public class PackageManagerService extends IPackageManager.Stub ipw.decreaseIndent(); } - if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) - && packageName == null) { + if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) { final String requiredVerifierPackage = mRequiredVerifierPackage; if (!checkin) { if (dumpState.onTitlePrinted()) { @@ -24895,8 +24894,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) - && packageName == null) { + if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) { final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy(); final ComponentName verifierComponent = proxy.getComponentName(); if (verifierComponent != null) { @@ -24923,13 +24921,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (dumpState.isDumping(DumpState.DUMP_LIBS) - && packageName == null) { + if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) { dump(DumpState.DUMP_LIBS, fd, pw, dumpState); } - if (dumpState.isDumping(DumpState.DUMP_FEATURES) - && packageName == null) { + if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) { if (dumpState.onTitlePrinted()) { pw.println(); } @@ -24939,7 +24935,12 @@ public class PackageManagerService extends IPackageManager.Stub synchronized (mAvailableFeatures) { for (FeatureInfo feat : mAvailableFeatures.values()) { - if (!checkin) { + if (checkin) { + pw.print("feat,"); + pw.print(feat.name); + pw.print(","); + pw.println(feat.version); + } else { pw.print(" "); pw.print(feat.name); if (feat.version > 0) { @@ -24947,73 +24948,55 @@ public class PackageManagerService extends IPackageManager.Stub pw.print(feat.version); } pw.println(); - } else { - pw.print("feat,"); - pw.print(feat.name); - pw.print(","); - pw.println(feat.version); } } } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName); } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName); } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName); } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) { synchronized (mLock) { mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName); } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_PREFERRED) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) { dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) { dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) { dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) { mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) { synchronized (mLock) { mComponentResolver.dumpContentProviders(pw, dumpState, packageName); } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_KEYSETS)) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) { synchronized (mLock) { mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState); } @@ -25028,15 +25011,11 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_QUERIES) - && packageName == null) { + if (dumpState.isDumping(DumpState.DUMP_QUERIES)) { dump(DumpState.DUMP_QUERIES, fd, pw, dumpState); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_SHARED_USERS) - && packageName == null) { + if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) { // This cannot be moved to ComputerEngine since the set of packages in the // SharedUserSetting do not have a copy. synchronized (mLock) { @@ -25044,9 +25023,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_CHANGES) - && packageName == null) { + if (dumpState.isDumping(DumpState.DUMP_CHANGES)) { if (dumpState.onTitlePrinted()) pw.println(); pw.println("Package Changes:"); synchronized (mLock) { @@ -25073,9 +25050,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_FROZEN) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) { // XXX should handle packageName != null by dumping only install data that // the given package is involved with. if (dumpState.onTitlePrinted()) pw.println(); @@ -25096,9 +25071,7 @@ public class PackageManagerService extends IPackageManager.Stub ipw.decreaseIndent(); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_VOLUMES) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) { if (dumpState.onTitlePrinted()) pw.println(); final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); @@ -25117,61 +25090,50 @@ public class PackageManagerService extends IPackageManager.Stub ipw.decreaseIndent(); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS) + if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS) && packageName == null) { synchronized (mLock) { mComponentResolver.dumpServicePermissions(pw, dumpState); } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_DEXOPT) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) { if (dumpState.onTitlePrinted()) pw.println(); dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) { if (dumpState.onTitlePrinted()) pw.println(); dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState); } - if (dumpState.isDumping(DumpState.DUMP_MESSAGES) - && packageName == null) { - if (!checkin) { - if (dumpState.onTitlePrinted()) pw.println(); - synchronized (mLock) { - mSettings.dumpReadMessagesLPr(pw, dumpState); - } - pw.println(); - pw.println("Package warning messages:"); - dumpCriticalInfo(pw, null); - } else { - dumpCriticalInfo(pw, "msg,"); + if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) { + if (dumpState.onTitlePrinted()) pw.println(); + synchronized (mLock) { + mSettings.dumpReadMessagesLPr(pw, dumpState); } + pw.println(); + pw.println("Package warning messages:"); + dumpCriticalInfo(pw, null); + } + + if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) { + dumpCriticalInfo(pw, "msg,"); } // PackageInstaller should be called outside of mPackages lock - if (!checkin - && dumpState.isDumping(DumpState.DUMP_INSTALLS) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) { // XXX should handle packageName != null by dumping only install data that // the given package is involved with. if (dumpState.onTitlePrinted()) pw.println(); mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120)); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_APEX) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) { mApexManager.dump(pw, packageName); } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS) + if (!checkin && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS) && packageName == null) { pw.println(); pw.println("Per UID read timeouts:"); @@ -25190,9 +25152,7 @@ public class PackageManagerService extends IPackageManager.Stub } } - if (!checkin - && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS) - && packageName == null) { + if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) { pw.println("Snapshot statistics"); if (!mSnapshotEnabled) { pw.println(" Snapshots disabled"); diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index bf82bd8b09d5..88dd03333262 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -176,6 +176,10 @@ public abstract class PackageSettingBase extends SettingBase { name = orig.name; realName = orig.realName; doCopy(orig); + // Clone the user states. + for (int i = 0; i < mUserState.size(); i++) { + mUserState.put(mUserState.keyAt(i), new PackageUserState(mUserState.valueAt(i))); + } } public void setInstallerPackageName(String packageName) { @@ -314,6 +318,7 @@ public abstract class PackageSettingBase extends SettingBase { void setInstalled(boolean inst, int userId) { modifyUserState(userId).installed = inst; + onChanged(); } boolean getInstalled(int userId) { @@ -326,6 +331,7 @@ public abstract class PackageSettingBase extends SettingBase { void setInstallReason(int installReason, int userId) { modifyUserState(userId).installReason = installReason; + onChanged(); } int getUninstallReason(int userId) { @@ -334,10 +340,13 @@ public abstract class PackageSettingBase extends SettingBase { void setUninstallReason(@UninstallReason int uninstallReason, int userId) { modifyUserState(userId).uninstallReason = uninstallReason; + onChanged(); } boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) { - return modifyUserState(userId).setOverlayPaths(overlayPaths); + boolean returnValue = modifyUserState(userId).setOverlayPaths(overlayPaths); + onChanged(); + return returnValue; } OverlayPaths getOverlayPaths(int userId) { @@ -346,7 +355,10 @@ public abstract class PackageSettingBase extends SettingBase { boolean setOverlayPathsForLibrary(String libName, OverlayPaths overlayPaths, int userId) { - return modifyUserState(userId).setSharedLibraryOverlayPaths(libName, overlayPaths); + boolean returnValue = modifyUserState(userId) + .setSharedLibraryOverlayPaths(libName, overlayPaths); + onChanged(); + return returnValue; } Map<String, OverlayPaths> getOverlayPathsForLibrary(int userId) { @@ -395,6 +407,7 @@ public abstract class PackageSettingBase extends SettingBase { void setCeDataInode(long ceDataInode, int userId) { modifyUserState(userId).ceDataInode = ceDataInode; + onChanged(); } boolean getStopped(int userId) { @@ -403,6 +416,7 @@ public abstract class PackageSettingBase extends SettingBase { void setStopped(boolean stop, int userId) { modifyUserState(userId).stopped = stop; + onChanged(); } boolean getNotLaunched(int userId) { @@ -411,6 +425,7 @@ public abstract class PackageSettingBase extends SettingBase { void setNotLaunched(boolean stop, int userId) { modifyUserState(userId).notLaunched = stop; + onChanged(); } boolean getHidden(int userId) { @@ -419,6 +434,7 @@ public abstract class PackageSettingBase extends SettingBase { void setHidden(boolean hidden, int userId) { modifyUserState(userId).hidden = hidden; + onChanged(); } int getDistractionFlags(int userId) { @@ -427,6 +443,7 @@ public abstract class PackageSettingBase extends SettingBase { void setDistractionFlags(int distractionFlags, int userId) { modifyUserState(userId).distractionFlags = distractionFlags; + onChanged(); } boolean getSuspended(int userId) { @@ -487,6 +504,7 @@ public abstract class PackageSettingBase extends SettingBase { void setInstantApp(boolean instantApp, int userId) { modifyUserState(userId).instantApp = instantApp; + onChanged(); } boolean getVirtulalPreload(int userId) { @@ -495,6 +513,7 @@ public abstract class PackageSettingBase extends SettingBase { void setVirtualPreload(boolean virtualPreload, int userId) { modifyUserState(userId).virtualPreload = virtualPreload; + onChanged(); } void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped, @@ -547,20 +566,24 @@ public abstract class PackageSettingBase extends SettingBase { void setEnabledComponents(ArraySet<String> components, int userId) { modifyUserState(userId).enabledComponents = components; + onChanged(); } void setDisabledComponents(ArraySet<String> components, int userId) { modifyUserState(userId).disabledComponents = components; + onChanged(); } void setEnabledComponentsCopy(ArraySet<String> components, int userId) { modifyUserState(userId).enabledComponents = components != null ? new ArraySet<String>(components) : null; + onChanged(); } void setDisabledComponentsCopy(ArraySet<String> components, int userId) { modifyUserState(userId).disabledComponents = components != null ? new ArraySet<String>(components) : null; + onChanged(); } PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) { @@ -582,10 +605,12 @@ public abstract class PackageSettingBase extends SettingBase { void addDisabledComponent(String componentClassName, int userId) { modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName); + onChanged(); } void addEnabledComponent(String componentClassName, int userId) { modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName); + onChanged(); } boolean enableComponentLPw(String componentClassName, int userId) { @@ -593,6 +618,9 @@ public abstract class PackageSettingBase extends SettingBase { boolean changed = state.disabledComponents != null ? state.disabledComponents.remove(componentClassName) : false; changed |= state.enabledComponents.add(componentClassName); + if (changed) { + onChanged(); + } return changed; } @@ -601,6 +629,9 @@ public abstract class PackageSettingBase extends SettingBase { boolean changed = state.enabledComponents != null ? state.enabledComponents.remove(componentClassName) : false; changed |= state.disabledComponents.add(componentClassName); + if (changed) { + onChanged(); + } return changed; } @@ -610,6 +641,9 @@ public abstract class PackageSettingBase extends SettingBase { ? state.disabledComponents.remove(componentClassName) : false; changed |= state.enabledComponents != null ? state.enabledComponents.remove(componentClassName) : false; + if (changed) { + onChanged(); + } return changed; } @@ -701,6 +735,7 @@ public abstract class PackageSettingBase extends SettingBase { PackageSettingBase setPath(@NonNull File path) { this.mPath = path; this.mPathString = path.toString(); + onChanged(); return this; } @@ -722,7 +757,9 @@ public abstract class PackageSettingBase extends SettingBase { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public boolean overrideNonLocalizedLabelAndIcon(@NonNull ComponentName component, @Nullable String label, @Nullable Integer icon, @UserIdInt int userId) { - return modifyUserState(userId).overrideLabelAndIcon(component, label, icon); + boolean returnValue = modifyUserState(userId).overrideLabelAndIcon(component, label, icon); + onChanged(); + return returnValue; } /** @@ -732,6 +769,7 @@ public abstract class PackageSettingBase extends SettingBase { */ public void resetOverrideComponentLabelIcon(@UserIdInt int userId) { modifyUserState(userId).resetOverrideComponentLabelIcon(); + onChanged(); } /** @@ -741,6 +779,7 @@ public abstract class PackageSettingBase extends SettingBase { */ public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) { modifyUserState(userId).splashScreenTheme = themeName; + onChanged(); } /** @@ -776,6 +815,7 @@ public abstract class PackageSettingBase extends SettingBase { */ public void setStatesOnCommit() { incrementalStates.onCommit(IncrementalManager.isIncrementalPath(getPathString())); + onChanged(); } /** @@ -783,6 +823,7 @@ public abstract class PackageSettingBase extends SettingBase { */ public void setIncrementalStatesCallback(IncrementalStates.Callback callback) { incrementalStates.setCallback(callback); + onChanged(); } /** @@ -791,6 +832,7 @@ public abstract class PackageSettingBase extends SettingBase { */ public void setLoadingProgress(float progress) { incrementalStates.setProgress(progress); + onChanged(); } public long getFirstInstallTime() { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 4c1142257218..1b799dfbdaab 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -733,15 +733,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp // dismissing during the task switching to keep the window focus because IME window has // higher window hierarchy, we don't give it focus if the next IME layering target // doesn't request IME visible. - if (w.mIsImWindow && (mImeLayeringTarget == null + if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null || !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) { - if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { - return false; - } - - if (w.isChildWindow()) { - return false; - } + return false; + } + if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG && mImeLayeringTarget != null + && !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME) + && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION, + ANIMATION_TYPE_APP_TRANSITION)) { + return false; } final ActivityRecord activity = w.mActivityRecord; diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index f2f192686ad5..11a0fba4b015 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -32,6 +32,10 @@ import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_B import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; +import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; +import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.StatusBarManager; @@ -211,7 +215,7 @@ class InsetsPolicy { InsetsState getInsetsForWindow(WindowState target) { final InsetsState originalState = mStateController.getInsetsForWindow(target); final InsetsState state = adjustVisibilityForTransientTypes(originalState); - return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; + return adjustVisibilityForIme(target, state, state == originalState); } /** @@ -241,16 +245,38 @@ class InsetsPolicy { return state; } - // Navigation bar insets is always visible to IME. - private static InsetsState adjustVisibilityForIme(InsetsState originalState, + private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState, boolean copyState) { - final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); - if (originalNavSource != null && !originalNavSource.isVisible()) { - final InsetsState state = copyState ? new InsetsState(originalState) : originalState; - final InsetsSource navSource = new InsetsSource(originalNavSource); - navSource.setVisible(true); - state.addSource(navSource); - return state; + if (w.mIsImWindow) { + // Navigation bar insets is always visible to IME. + final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); + if (originalNavSource != null && !originalNavSource.isVisible()) { + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + final InsetsSource navSource = new InsetsSource(originalNavSource); + navSource.setVisible(true); + state.addSource(navSource); + return state; + } + } else if (w.mActivityRecord != null && !w.mActivityRecord.mLastImeShown) { + // During switching tasks with gestural navigation, if the IME is attached to + // one app window on that time, even the next app window is behind the IME window, + // conceptually the window should not receive the IME insets if the next window is + // not eligible IME requester and ready to show IME on top of it. + final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp(); + final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME); + + if (originalImeSource != null && shouldImeAttachedToApp + && (w.isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS) + || !w.getRequestedVisibility(ITYPE_IME))) { + final InsetsState state = copyState ? new InsetsState(originalState) + : originalState; + + final InsetsSource imeSource = new InsetsSource(originalImeSource); + imeSource.setVisible(false); + state.addSource(imeSource); + return state; + } } return originalState; } diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java index c12eb32a9143..e98a4dded99b 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java +++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java @@ -64,12 +64,16 @@ public class AppOpsStartedWatcherTest { .times(1)).onOpStarted(eq(AppOpsManager.OP_FINE_LOCATION), eq(Process.myUid()), eq(getContext().getPackageName()), eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF), - eq(AppOpsManager.MODE_ALLOWED)); + eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED), + eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE), + eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE)); inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS) .times(1)).onOpStarted(eq(AppOpsManager.OP_CAMERA), eq(Process.myUid()), eq(getContext().getPackageName()), eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF), - eq(AppOpsManager.MODE_ALLOWED)); + eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED), + eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE), + eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE)); // Stop watching appOpsManager.stopWatchingStarted(listener); @@ -94,7 +98,9 @@ public class AppOpsStartedWatcherTest { .times(2)).onOpStarted(eq(AppOpsManager.OP_CAMERA), eq(Process.myUid()), eq(getContext().getPackageName()), eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF), - eq(AppOpsManager.MODE_ALLOWED)); + eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED), + eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE), + eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE)); verifyNoMoreInteractions(listener); // Finish up diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java index 7f5f3c2df077..1263f7b84db1 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java @@ -255,13 +255,16 @@ public class CoexCoordinatorTest { mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient); mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient); + // For easier reading + final CoexCoordinator.Callback faceCallback = mCallback; + mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient, - mCallback); - verify(mCallback, never()).sendHapticFeedback(); - verify(mCallback, never()).sendAuthenticationResult(anyBoolean()); + faceCallback); + verify(faceCallback, never()).sendHapticFeedback(); + verify(faceCallback, never()).sendAuthenticationResult(anyBoolean()); // CoexCoordinator requests the system to hold onto this AuthenticationClient until // UDFPS result is known - verify(mCallback, never()).handleLifecycleAfterAuth(); + verify(faceCallback, never()).handleLifecycleAfterAuth(); // Reset the mock CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class); @@ -274,6 +277,8 @@ public class CoexCoordinatorTest { verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */); verify(udfpsCallback).handleLifecycleAfterAuth(); + verify(faceCallback).sendAuthenticationCanceled(); + assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty()); } else { mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient, @@ -281,16 +286,16 @@ public class CoexCoordinatorTest { if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) { verify(udfpsCallback, never()).sendHapticFeedback(); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); + verify(faceCallback).sendHapticFeedback(); + verify(faceCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */); + verify(faceCallback).handleLifecycleAfterAuth(); assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty()); } else { assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty()); - verify(mCallback, never()).sendHapticFeedback(); - verify(mCallback, never()).sendAuthenticationResult(anyBoolean()); + verify(faceCallback, never()).sendHapticFeedback(); + verify(faceCallback, never()).sendAuthenticationResult(anyBoolean()); verify(udfpsCallback).sendHapticFeedback(); verify(udfpsCallback) diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index c60b8dcf67cf..12fc2f4ea1f4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2223,6 +2223,9 @@ public class DisplayContentTests extends WindowTestsBase { // request IME visible. final WindowState nextImeAppTarget = createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget"); + spyOn(nextImeAppTarget); + doReturn(true).when(nextImeAppTarget).isAnimating(PARENTS | TRANSITION, + ANIMATION_TYPE_APP_TRANSITION); mDisplayContent.setImeLayeringTarget(nextImeAppTarget); assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 92b670ed9699..3a50bb0f06bc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -53,6 +53,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL; import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS; +import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; +import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW; import static com.google.common.truth.Truth.assertThat; @@ -891,6 +894,36 @@ public class WindowStateTests extends WindowTestsBase { assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); } + @UseTestDisplay(addWindows = W_INPUT_METHOD) + @Test + public void testAdjustImeInsetsVisibilityWhenTaskSwitchIsAnimating() { + final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); + final InsetsStateController controller = mDisplayContent.getInsetsStateController(); + controller.getImeSourceProvider().setWindow(mImeWindow, null, null); + + // Simulate app requests IME with updating all windows Insets State when IME is above app. + mDisplayContent.setImeLayeringTarget(app); + mDisplayContent.setImeInputTarget(app); + assertTrue(mDisplayContent.shouldImeAttachedToApp()); + controller.getImeSourceProvider().scheduleShowImePostLayout(app); + controller.getImeSourceProvider().getSource().setVisible(true); + controller.updateAboveInsetsState(mImeWindow, false); + + // Simulate task switching animation happens when switching app to app2. + spyOn(app); + spyOn(app2); + doReturn(true).when(app).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS); + doReturn(true).when(app2).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS); + app.mActivityRecord.mLastImeShown = true; + + // Verify the IME insets is visible on app, but not for app2 during task animating. + InsetsState stateApp = app.getInsetsState(); + InsetsState stateApp2 = app2.getInsetsState(); + assertTrue(stateApp.getSource(ITYPE_IME).isVisible()); + assertFalse(stateApp2.getSource(ITYPE_IME).isVisible()); + } + @UseTestDisplay(addWindows = { W_ACTIVITY }) @Test public void testUpdateImeControlTargetWhenLeavingMultiWindow() { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 71541ad729d5..9ea2b7b12ad0 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -1896,17 +1896,19 @@ public class VoiceInteractionManagerService extends SystemService { String serviceComponentName = serviceInfo.getComponentName() .flattenToShortString(); - - String serviceRecognizerName = new ComponentName(pkg, - voiceInteractionServiceInfo.getRecognitionService()) - .flattenToShortString(); + if (voiceInteractionServiceInfo.getRecognitionService() == null) { + Slog.e(TAG, "The RecognitionService must be set to avoid boot " + + "loop on earlier platform version. Also make sure that this " + + "is a valid RecognitionService when running on Android 11 " + + "or earlier."); + serviceComponentName = ""; + } Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.ASSISTANT, serviceComponentName, userId); Settings.Secure.putStringForUser(getContext().getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName, userId); - return; } @@ -1947,6 +1949,29 @@ public class VoiceInteractionManagerService extends SystemService { } } + private void resetServicesIfNoRecognitionService(ComponentName serviceComponent, + int userHandle) { + for (ResolveInfo resolveInfo : queryInteractorServices(userHandle, + serviceComponent.getPackageName())) { + VoiceInteractionServiceInfo serviceInfo = + new VoiceInteractionServiceInfo( + mContext.getPackageManager(), + resolveInfo.serviceInfo); + if (!serviceInfo.getSupportsAssist()) { + continue; + } + if (serviceInfo.getRecognitionService() == null) { + Slog.e(TAG, "The RecognitionService must be set to " + + "avoid boot loop on earlier platform version. " + + "Also make sure that this is a valid " + + "RecognitionService when running on Android 11 " + + "or earlier."); + setCurInteractor(null, userHandle); + resetCurAssistant(userHandle); + } + } + } + PackageMonitor mPackageMonitor = new PackageMonitor() { @Override public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { @@ -2090,6 +2115,7 @@ public class VoiceInteractionManagerService extends SystemService { change = isPackageAppearing(curInteractor.getPackageName()); if (change != PACKAGE_UNCHANGED) { + resetServicesIfNoRecognitionService(curInteractor, userHandle); // If current interactor is now appearing, for any reason, then // restart our connection with it. if (mImpl != null && curInteractor.getPackageName().equals( @@ -2112,6 +2138,13 @@ public class VoiceInteractionManagerService extends SystemService { initForUser(userHandle); return; } + change = isPackageAppearing(curAssistant.getPackageName()); + if (change != PACKAGE_UNCHANGED) { + // It is possible to update Assistant without a voice interactor to one + // with a voice-interactor. We should make sure the recognition service + // is set to avoid boot loop. + resetServicesIfNoRecognitionService(curAssistant, userHandle); + } } // There is no interactor, so just deal with a simple recognizer. |