Merge tag 'android-security-15.0.0_r10' into staging/lineage-22.2_merge-android-security-15.0.0_r10

Android Security 15.0.0 Release 10 (13793697)

# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCaLciswAKCRDorT+BmrEO
# eIteAJ96gVr8EH2JegpLjuR6Q9TFzzcukgCgiLGp/vd6l1MLGg7gV1ipJ4WIooM=
# =sCKm
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue Sep  2 20:00:35 2025 EEST
# gpg:                using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Good signature from "The Android Open Source Project <initial-contribution@android.com>" [ultimate]

* tag 'android-security-15.0.0_r10':
  [RESTRICT AUTOMERGE] Fix audio AppOps refcount mismatch
  [RESTRICT AUTOMERGE] Validate full attr chain for recording

 Conflicts:
	media/utils/ServiceUtilities.cpp
	services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
	services/audiopolicy/service/AudioRecordClient.cpp

Change-Id: I34851e8fb1a0faea0ba3446f5a4656d3cad29535
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 7fd5be5..81662f1 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -172,9 +172,28 @@
         permission::PermissionChecker permissionChecker;
         int permitted;
         if (start) {
-            permitted = permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
+            // Do a double-check, where we first check without actually starting in order to handle
+            // the behavior of AppOps where ops are sometimes started but paused for SOFT_DENIED.
+            // Since there is no way to maintain reference consensus due to this behavior, avoid
+            // starting an op when a restriction is in place by first checking. In the case where we
+            // startOp would fail, call a noteOp (which will also fail) instead. This preserves
+            // behavior that is reliant on listening to op rejected events (such as the hint
+            // dialogue to unmute the microphone). Technically racy, but very unlikely.
+            //
+            // TODO(b/294609684) To be removed when the pause state for an OP is removed.
+            permitted = permissionChecker.checkPermissionForPreflightFromDatasource(
                     sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
                     attributedOpCode);
+            if (permitted == PERMISSION_GRANTED) {
+                permitted = permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
+                        sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
+                        attributedOpCode);
+            } else {
+                // intentionally don't set permitted
+                permissionChecker.checkPermissionForDataDeliveryFromDatasource(
+                            sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
+                            attributedOpCode);
+            }
         } else {
             permitted = permissionChecker.checkPermissionForPreflightFromDatasource(
                     sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp
index 79a7458..aec43ca 100644
--- a/services/audiopolicy/service/AudioRecordClient.cpp
+++ b/services/audiopolicy/service/AudioRecordClient.cpp
@@ -50,7 +50,7 @@
         if (pm != nullptr) {
             const auto status = pm->getTargetSdkVersionForPackage(
                     String16{packageName.data(), packageName.size()}, &targetSdk);
-            return status.isOk() ? targetSdk : -1;
+            return status.isOk() ? targetSdk : __ANDROID_API_FUTURE__;
         }
     }
     return targetSdk;