Merge "Add some binder transaction info when dumping backtraces for ANR" into main
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index ece8851..79373a5 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -9,6 +9,7 @@
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public android.nfc.NfcOemExtension getNfcOemExtension();
     method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
@@ -46,6 +47,16 @@
     method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciResponse(@IntRange(from=0, to=15) int, int, @NonNull byte[]);
   }
 
+  @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
+  }
+
+  public static interface NfcOemExtension.Callback {
+    method public void onTagConnected(boolean, @NonNull android.nfc.Tag);
+  }
+
 }
 
 package android.nfc.cardemulation {
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 8fea5af..bde63c3 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -28,6 +28,7 @@
 import android.nfc.INfcTag;
 import android.nfc.INfcCardEmulation;
 import android.nfc.INfcFCardEmulation;
+import android.nfc.INfcOemExtensionCallback;
 import android.nfc.INfcUnlockHandler;
 import android.nfc.ITagRemovedCallback;
 import android.nfc.INfcDta;
@@ -91,4 +92,7 @@
     int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload);
     void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks);
     void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks);
+    void registerOemExtensionCallback(INfcOemExtensionCallback callbacks);
+    void unregisterOemExtensionCallback(INfcOemExtensionCallback callbacks);
+    void clearPreference();
 }
diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
new file mode 100644
index 0000000..6c9096d
--- /dev/null
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.nfc;
+
+import android.nfc.Tag;
+
+/**
+ * @hide
+ */
+interface INfcOemExtensionCallback {
+   void onTagConnected(boolean connected, in Tag tag);
+}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 40bbe74..7e0a111 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -556,6 +556,7 @@
     final Context mContext;
     final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
     final Object mLock;
+    final NfcOemExtension mNfcOemExtension;
 
     ITagRemovedCallback mTagRemovedListener; // protected by mLock
 
@@ -864,6 +865,7 @@
         mLock = new Object();
         mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
         mNfcVendorNciCallbackListener = new NfcVendorNciCallbackListener(getService());
+        mNfcOemExtension = new NfcOemExtension(mContext, this);
     }
 
     /**
@@ -2919,4 +2921,19 @@
         void onVendorNciNotification(
                 @IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
     }
+
+    /**
+     * Returns an instance of {@link NfcOemExtension} associated with {@link NfcAdapter} instance.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @NonNull public NfcOemExtension getNfcOemExtension() {
+        synchronized (sLock) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
+        return mNfcOemExtension;
+    }
 }
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
new file mode 100644
index 0000000..1eff58c
--- /dev/null
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Used for OEM extension APIs.
+ * This class holds all the APIs and callbacks defined for OEMs/vendors to extend the NFC stack
+ * for their proprietary features.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+@SystemApi
+public final class NfcOemExtension {
+    private static final String TAG = "NfcOemExtension";
+    private static final int OEM_EXTENSION_RESPONSE_THRESHOLD_MS = 2000;
+    private final NfcAdapter mAdapter;
+    private final NfcOemExtensionCallback mOemNfcExtensionCallback;
+    private final Context mContext;
+    private Executor mExecutor = null;
+    private Callback mCallback = null;
+    private final Object mLock = new Object();
+
+    /**
+     * Interface for Oem extensions for NFC.
+     */
+    public interface Callback {
+        /**
+         * Notify Oem to tag is connected or not
+         * ex - if tag is connected  notify cover and Nfctest app if app is in testing mode
+         *
+         * @param connected status of the tag true if tag is connected otherwise false
+         * @param tag Tag details
+         */
+        void onTagConnected(boolean connected, @NonNull Tag tag);
+    }
+
+
+    /**
+     * Constructor to be used only by {@link NfcAdapter}.
+     * @hide
+     */
+    public NfcOemExtension(@NonNull Context context, @NonNull NfcAdapter adapter) {
+        mContext = context;
+        mAdapter = adapter;
+        mOemNfcExtensionCallback = new NfcOemExtensionCallback();
+    }
+
+    /**
+     * Register an {@link Callback} to listen for UWB oem extension callbacks
+     * <p>The provided callback will be invoked by the given {@link Executor}.
+     *
+     * @param executor an {@link Executor} to execute given callback
+     * @param callback oem implementation of {@link Callback}
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public void registerCallback(@NonNull @CallbackExecutor Executor executor,
+            @NonNull Callback callback) {
+        synchronized (mLock) {
+            if (mCallback != null) {
+                Log.e(TAG, "Callback already registered. Unregister existing callback before"
+                        + "registering");
+                throw new IllegalArgumentException();
+            }
+            try {
+                NfcAdapter.sService.registerOemExtensionCallback(mOemNfcExtensionCallback);
+                mCallback = callback;
+                mExecutor = executor;
+            } catch (RemoteException e) {
+                mAdapter.attemptDeadServiceRecovery(e);
+            }
+        }
+    }
+
+    /**
+     * Unregister the specified {@link Callback}
+     *
+     * <p>The same {@link Callback} object used when calling
+     * {@link #registerCallback(Executor, Callback)} must be used.
+     *
+     * <p>Callbacks are automatically unregistered when an application process goes away
+     *
+     * @param callback oem implementation of {@link Callback}
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public void unregisterCallback(@NonNull Callback callback) {
+        synchronized (mLock) {
+            if (mCallback == null || mCallback != callback) {
+                Log.e(TAG, "Callback not registered");
+                throw new IllegalArgumentException();
+            }
+            try {
+                NfcAdapter.sService.unregisterOemExtensionCallback(mOemNfcExtensionCallback);
+                mCallback = null;
+                mExecutor = null;
+            } catch (RemoteException e) {
+                mAdapter.attemptDeadServiceRecovery(e);
+            }
+        }
+    }
+
+    /**
+     * Clear NfcService preference, interface method to clear NFC preference values on OEM specific
+     * events. For ex: on soft reset, Nfc default values needs to be overridden by OEM defaults.
+     */
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public void clearPreference() {
+        try {
+            NfcAdapter.sService.clearPreference();
+        } catch (RemoteException e) {
+            mAdapter.attemptDeadServiceRecovery(e);
+        }
+    }
+
+    private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
+        @Override
+        public void onTagConnected(boolean connected, Tag tag) throws RemoteException {
+            synchronized (mLock) {
+                if (mCallback == null || mExecutor == null) {
+                    return;
+                }
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    mExecutor.execute(() -> mCallback.onTagConnected(connected, tag));
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+        }
+    }
+}
diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 44924ae..5879595 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -76,3 +76,11 @@
     description: "Enable NFC vendor command support"
     bug: "289879306"
 }
+
+flag {
+    name: "nfc_oem_extension"
+    is_exported: true
+    namespace: "nfc"
+    description: "Enable NFC OEM extension support"
+    bug: "331206243"
+}
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
index 8266299..b55f35d 100644
--- a/services/core/java/com/android/server/am/LmkdStatsReporter.java
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -34,7 +34,6 @@
     static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdStatsReporter" : TAG_AM;
 
     public static final int KILL_OCCURRED_MSG_SIZE = 80;
-    public static final int STATE_CHANGED_MSG_SIZE = 8;
 
     private static final int PRESSURE_AFTER_KILL = 0;
     private static final int NOT_RESPONDING = 1;
@@ -80,16 +79,6 @@
         }
     }
 
-    /**
-     * Processes the LMK_STATE_CHANGED packet
-     * Logs the change in LMKD state which is used as start/stop boundaries for logging
-     * LMK_KILL_OCCURRED event.
-     * Code: LMK_STATE_CHANGED = 54
-     */
-    public static void logStateChanged(int state) {
-        FrameworkStatsLog.write(FrameworkStatsLog.LMK_STATE_CHANGED, state);
-    }
-
     private static int mapKillReason(int reason) {
         switch (reason) {
             case PRESSURE_AFTER_KILL:
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 65c2cc5..e876527 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -349,7 +349,7 @@
     // LMK_PROCKILL
     // LMK_UPDATE_PROPS
     // LMK_KILL_OCCURRED
-    // LMK_STATE_CHANGED
+    // LMK_START_MONITORING
     static final byte LMK_TARGET = 0;
     static final byte LMK_PROCPRIO = 1;
     static final byte LMK_PROCREMOVE = 2;
@@ -359,7 +359,6 @@
     static final byte LMK_PROCKILL = 6; // Note: this is an unsolicited command
     static final byte LMK_UPDATE_PROPS = 7;
     static final byte LMK_KILL_OCCURRED = 8; // Msg to subscribed clients on kill occurred event
-    static final byte LMK_STATE_CHANGED = 9; // Msg to subscribed clients on state changed
     static final byte LMK_START_MONITORING = 9; // Start monitoring if delayed earlier
 
     // Low Memory Killer Daemon command codes.
@@ -960,14 +959,6 @@
                                                 foregroundServices.first,
                                                 foregroundServices.second);
                                         return true;
-                                    case LMK_STATE_CHANGED:
-                                        if (receivedLen
-                                                != LmkdStatsReporter.STATE_CHANGED_MSG_SIZE) {
-                                            return false;
-                                        }
-                                        final int state = inputData.readInt();
-                                        LmkdStatsReporter.logStateChanged(state);
-                                        return true;
                                     default:
                                         return false;
                                 }