Merge "Add more access annotations." into main
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
new file mode 100755
index 0000000..88b7a42
--- /dev/null
+++ b/compatibility_matrices/bump.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""
+Creates the next compatibility matrix.
+
+Requires libvintf Level.h to be updated before executing this script.
+"""
+
+import argparse
+import os
+import pathlib
+import shutil
+import subprocess
+import textwrap
+
+
+def check_call(*args, **kwargs):
+    print(args)
+    subprocess.check_call(*args, **kwargs)
+
+
+def check_output(*args, **kwargs):
+    print(args)
+    return subprocess.check_output(*args, **kwargs)
+
+
+class Bump(object):
+
+    def __init__(self, cmdline_args):
+        self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"])
+        self.interfaces_dir = self.top / "hardware/interfaces"
+
+        self.current_level = cmdline_args.current
+        self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
+        self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
+
+        self.next_level = cmdline_args.next
+        self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml"
+        self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml"
+
+        self.level_to_letter = self.get_level_to_letter_mapping()
+        print("Found level mapping in libvintf Level.h:", self.level_to_letter)
+
+    def run(self):
+        self.bump_kernel_configs()
+        self.copy_matrix()
+        self.edit_android_bp()
+        self.edit_android_mk()
+
+    def get_level_to_letter_mapping(self):
+        levels_file = self.top / "system/libvintf/include/vintf/Level.h"
+        with open(levels_file) as f:
+            lines = f.readlines()
+            pairs = [
+                line.split("=", maxsplit=2) for line in lines if "=" in line
+            ]
+            return {
+                level.strip().removesuffix(","): letter.strip()
+                for letter, level in pairs
+            }
+
+    def bump_kernel_configs(self):
+        check_call([
+            self.top / "kernel/configs/tools/bump.py",
+            self.level_to_letter[self.current_level].lower(),
+            self.level_to_letter[self.next_level].lower(),
+        ])
+
+    def copy_matrix(self):
+        shutil.copyfile(self.current_xml, self.next_xml)
+
+    def edit_android_bp(self):
+        android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp"
+
+        with open(android_bp, "r+") as f:
+            if self.next_module_name not in f.read():
+                f.seek(0, 2)  # end of file
+                f.write("\n")
+                f.write(
+                    textwrap.dedent(f"""\
+                        vintf_compatibility_matrix {{
+                            name: "{self.next_module_name}",
+                        }}
+                    """))
+
+        next_kernel_configs = check_output(
+            """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
+            cwd=self.top / "kernel/configs" /
+            self.level_to_letter[self.next_level].lower(),
+            text=True,
+            shell=True,
+        ).splitlines()
+        print(next_kernel_configs)
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem",
+            "-str", self.next_xml.name, android_bp
+        ])
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs",
+            "-a",
+            self.next_xml.relative_to(android_bp.parent), android_bp
+        ])
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property",
+            "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
+        ])
+
+    def edit_android_mk(self):
+        android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk"
+        with open(android_mk) as f:
+            if self.next_module_name in f.read():
+                return
+            f.seek(0)
+            lines = f.readlines()
+        current_module_line_number = None
+        for line_number, line in enumerate(lines):
+            if self.current_module_name in line:
+                current_module_line_number = line_number
+                break
+        assert current_module_line_number is not None
+        lines.insert(current_module_line_number + 1,
+                     f"    {self.next_module_name} \\\n")
+        with open(android_mk, "w") as f:
+            f.write("".join(lines))
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("current",
+                        type=str,
+                        help="VINTF level of the current version (e.g. 9)")
+    parser.add_argument("next",
+                        type=str,
+                        help="VINTF level of the next version (e.g. 10)")
+    cmdline_args = parser.parse_args()
+
+    Bump(cmdline_args).run()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
index e4d4cbe..607ceb3 100644
--- a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
@@ -36,10 +36,9 @@
 interface IThreadChip {
   void open(in android.hardware.threadnetwork.IThreadChipCallback callback);
   void close();
-  void reset();
+  void hardwareReset();
   void sendSpinelFrame(in byte[] frame);
   const int ERROR_FAILED = 1;
-  const int ERROR_INVALID_ARGS = 2;
-  const int ERROR_NO_BUFS = 3;
-  const int ERROR_BUSY = 4;
+  const int ERROR_NO_BUFS = 2;
+  const int ERROR_BUSY = 3;
 }
diff --git a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
index eebaa46..e695623 100644
--- a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
@@ -30,19 +30,14 @@
     const int ERROR_FAILED = 1;
 
     /**
-     * The invalid arguments.
-     */
-    const int ERROR_INVALID_ARGS = 2;
-
-    /**
      * Insufficient buffers available to send frames.
      */
-    const int ERROR_NO_BUFS = 3;
+    const int ERROR_NO_BUFS = 2;
 
     /**
      * Service is busy and could not service the operation.
      */
-    const int ERROR_BUSY = 4;
+    const int ERROR_BUSY = 3;
 
     /**
      * This method initializes the Thread HAL instance. If open completes
@@ -51,9 +46,10 @@
      *
      * @param callback  A IThreadChipCallback callback instance.
      *
+     * @throws EX_ILLEGAL_ARGUMENT  if the callback handle is invalid (for example, it is null).
+     *
      * @throws ServiceSpecificException with one of the following values:
      *     - ERROR_FAILED        The interface cannot be opened due to an internal error.
-     *     - ERROR_INVALID_ARGS  The callback handle is invalid (for example, it is null).
      *     - ERROR_BUSY          This interface is in use.
      */
     void open(in IThreadChipCallback callback);
@@ -64,11 +60,14 @@
     void close();
 
     /**
-     * This method resets the Thread HAL internal state. The callback registered by
-     * `open()` won’t be reset and the resource allocated by `open()` won’t be free.
+     * This method hardware resets the Thread radio chip via the physical reset pin.
+     * The callback registered by `open()` won’t be reset and the resource allocated
+     * by `open()` won’t be free.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION  if the Thread radio chip doesn't support the hardware reset.
      *
      */
-    void reset();
+    void hardwareReset();
 
     /**
      * This method sends a spinel frame to the Thread HAL.
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 8b938d2..bcd5704 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -79,7 +79,6 @@
         "fuzzer.cpp",
     ],
 
-    required: ["ot-rcp"],
     fuzz_config: {
         cc: [
             "zhanglongxia@google.com",
diff --git a/threadnetwork/aidl/default/fuzzer.cpp b/threadnetwork/aidl/default/fuzzer.cpp
index 512708d..fb6e548 100644
--- a/threadnetwork/aidl/default/fuzzer.cpp
+++ b/threadnetwork/aidl/default/fuzzer.cpp
@@ -22,7 +22,7 @@
 using android::fuzzService;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    char url[] = "spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=2";
+    char url[] = "spinel+hdlc+null:///dev/null";
     auto service = ndk::SharedRefBase::make<ThreadChip>(url);
 
     fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
index 94d1e93..3d38cb8 100644
--- a/threadnetwork/aidl/default/thread_chip.cpp
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -17,6 +17,8 @@
 #include "thread_chip.hpp"
 
 #include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <utils/Log.h>
@@ -46,20 +48,36 @@
         mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(handleReceivedFrameJump, this,
                                                                       mRxFrameBuffer);
     } else {
-        ALOGE("The protocol \"%s\" is not supported!", protocol);
-        exit(1);
+        ALOGE("The protocol \"%s\" is not supported", protocol);
+        exit(EXIT_FAILURE);
     }
 
     CHECK_NE(mSpinelInterface, nullptr);
+
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
+    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
 }
 
-void ThreadChip::clientDeathCallback(void* context) {
-    reinterpret_cast<ThreadChip*>(context)->clientDeathCallback();
+ThreadChip::~ThreadChip() {
+    AIBinder_DeathRecipient_delete(mDeathRecipient.get());
 }
 
-void ThreadChip::clientDeathCallback(void) {
-    ALOGW("Thread Network HAL client is dead.");
-    close();
+void ThreadChip::onBinderDiedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderDied();
+}
+
+void ThreadChip::onBinderDied(void) {
+    ALOGW("Thread Network HAL client is dead");
+}
+
+void ThreadChip::onBinderUnlinkedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
+}
+
+void ThreadChip::onBinderUnlinked(void) {
+    ALOGW("ThreadChip binder is unlinked");
+    deinitChip();
 }
 
 void ThreadChip::handleReceivedFrameJump(void* context) {
@@ -76,75 +94,83 @@
 }
 
 ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
-    ndk::ScopedAStatus status;
-    AIBinder* binder;
+    ndk::ScopedAStatus status = initChip(in_callback);
 
-    VerifyOrExit(mCallback == nullptr,
-                 status = errorStatus(ERROR_BUSY, "Interface is already opened"));
-    VerifyOrExit(in_callback != nullptr,
-                 status = errorStatus(ERROR_INVALID_ARGS, "The callback is NULL"));
-    binder = in_callback->asBinder().get();
-    VerifyOrExit(binder != nullptr,
-                 status = errorStatus(ERROR_FAILED, "Failed to get the callback binder"));
-    mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback);
-    VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK,
-                 status = errorStatus(ERROR_FAILED, "Failed to link the binder to death"));
-    VerifyOrExit(mSpinelInterface->Init(mUrl) == OT_ERROR_NONE,
-                 status = errorStatus(ERROR_FAILED, "Failed to initialize the interface"));
-
-    mCallback = in_callback;
-    ot::Posix::Mainloop::Manager::Get().Add(*this);
-    status = ndk::ScopedAStatus::ok();
-
-exit:
-    if (!status.isOk()) {
-        if (mBinderDeathRecipient != nullptr) {
-            AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
-            mBinderDeathRecipient = nullptr;
-        }
-        ALOGW("Open failed, error: %s", status.getDescription().c_str());
+    if (status.isOk()) {
+        AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
+        ALOGI("Open IThreadChip successfully");
     } else {
-        ALOGI("open()");
+        ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
     }
 
     return status;
 }
 
+ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    } else if (mCallback == nullptr) {
+        if (mSpinelInterface->Init(mUrl) != OT_ERROR_NONE) {
+            return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
+        }
+
+        mCallback = in_callback;
+        ot::Posix::Mainloop::Manager::Get().Add(*this);
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return errorStatus(ERROR_BUSY, "Interface has been opened");
+    }
+}
+
 ndk::ScopedAStatus ThreadChip::close() {
-    VerifyOrExit(mCallback != nullptr);
-    mCallback = nullptr;
-    mSpinelInterface->Deinit();
+    ndk::ScopedAStatus status;
+    std::shared_ptr<IThreadChipCallback> callback = mCallback;
 
-    ot::Posix::Mainloop::Manager::Get().Remove(*this);
+    status = deinitChip();
+    if (status.isOk()) {
+        if (callback != nullptr) {
+            AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
+        }
 
-    AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
-    mBinderDeathRecipient = nullptr;
+        ALOGI("Close IThreadChip successfully");
+    } else {
+        ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
+    }
 
-exit:
-    ALOGI("close()");
-    return ndk::ScopedAStatus::ok();
+    return status;
+}
+
+ndk::ScopedAStatus ThreadChip::deinitChip() {
+    if (mCallback != nullptr) {
+        mSpinelInterface->Deinit();
+        ot::Posix::Mainloop::Manager::Get().Remove(*this);
+        mCallback = nullptr;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
 }
 
 ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
     ndk::ScopedAStatus status;
     otError error;
 
-    VerifyOrExit(mCallback != nullptr,
-                 status = errorStatus(ERROR_FAILED, "The interface is not open"));
-
-    error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
-                                        in_frame.size());
-    if (error == OT_ERROR_NONE) {
-        status = ndk::ScopedAStatus::ok();
-    } else if (error == OT_ERROR_NO_BUFS) {
-        status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
-    } else if (error == OT_ERROR_BUSY) {
-        status = errorStatus(ERROR_BUSY, "The interface is busy");
+    if (mCallback == nullptr) {
+        status = errorStatus(ERROR_FAILED, "The interface is not open");
     } else {
-        status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+        error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
+                                            in_frame.size());
+        if (error == OT_ERROR_NONE) {
+            status = ndk::ScopedAStatus::ok();
+        } else if (error == OT_ERROR_NO_BUFS) {
+            status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
+        } else if (error == OT_ERROR_BUSY) {
+            status = errorStatus(ERROR_BUSY, "The interface is busy");
+        } else {
+            status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+        }
     }
 
-exit:
     if (!status.isOk()) {
         ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
     }
@@ -152,8 +178,11 @@
     return status;
 }
 
-ndk::ScopedAStatus ThreadChip::reset() {
-    mSpinelInterface->HardwareReset();
+ndk::ScopedAStatus ThreadChip::hardwareReset() {
+    if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+
     ALOGI("reset()");
     return ndk::ScopedAStatus::ok();
 }
diff --git a/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
index 294190a..1ab6d54 100644
--- a/threadnetwork/aidl/default/thread_chip.hpp
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -22,6 +22,7 @@
 #include "lib/spinel/spinel_interface.hpp"
 #include "mainloop.hpp"
 
+#include <android/binder_auto_utils.h>
 #include <android/binder_ibinder.h>
 #include <utils/Mutex.h>
 
@@ -33,26 +34,31 @@
 class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
   public:
     ThreadChip(char* url);
+    ~ThreadChip();
 
     ndk::ScopedAStatus open(const std::shared_ptr<IThreadChipCallback>& in_callback) override;
     ndk::ScopedAStatus close() override;
     ndk::ScopedAStatus sendSpinelFrame(const std::vector<uint8_t>& in_frame) override;
-    ndk::ScopedAStatus reset() override;
+    ndk::ScopedAStatus hardwareReset() override;
     void Update(otSysMainloopContext& context) override;
     void Process(const otSysMainloopContext& context) override;
 
   private:
-    static void clientDeathCallback(void* context);
-    void clientDeathCallback(void);
+    static void onBinderDiedJump(void* context);
+    void onBinderDied(void);
+    static void onBinderUnlinkedJump(void* context);
+    void onBinderUnlinked(void);
     static void handleReceivedFrameJump(void* context);
     void handleReceivedFrame(void);
     ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
+    ndk::ScopedAStatus initChip(const std::shared_ptr<IThreadChipCallback>& in_callback);
+    ndk::ScopedAStatus deinitChip();
 
     ot::Url::Url mUrl;
     std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
     ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
     std::shared_ptr<IThreadChipCallback> mCallback;
-    AIBinder_DeathRecipient* mBinderDeathRecipient;
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
 };
 
 }  // namespace threadnetwork
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
index 04c6dea..5925b54 100644
--- a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -91,7 +91,7 @@
             ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
 
     EXPECT_TRUE(thread_chip->open(callback).isOk());
-    EXPECT_TRUE(thread_chip->reset().isOk());
+    EXPECT_TRUE(thread_chip->hardwareReset().isOk());
 }
 
 TEST_P(ThreadNetworkAidl, SendSpinelFrame) {