Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 897c6c67 authored by Devin Moore's avatar Devin Moore Committed by Gerrit Code Review
Browse files

Merge "Add PersistableBundle ndk and AIDL type" into main

parents dd07deae 33ce330d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -89,6 +89,12 @@ filegroup {
    ],
}

aidl_library {
    name: "PersistableBundle_aidl",
    hdrs: ["aidl/binder/android/os/PersistableBundle.aidl"],
    strip_import_prefix: "aidl/binder",
}

cc_library_headers {
    name: "libandroid_headers_private",
    export_include_dirs: ["include/private"],
+1 −1
Original line number Diff line number Diff line
@@ -17,4 +17,4 @@

package android.os;

@JavaOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable PersistableBundle cpp_header "binder/PersistableBundle.h" ndk_header "android/persistable_bundle_aidl.h";
+1 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ cc_library {
        "libbinder.cpp",
        "parcel.cpp",
        "parcel_jni.cpp",
        "persistable_bundle.cpp",
        "process.cpp",
        "stability.cpp",
        "status.cpp",
+497 −0
Original line number Diff line number Diff line
/*
 * 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.
 */
#pragma once

#include <android/binder_parcel.h>
#include <android/persistable_bundle.h>
#include <sys/cdefs.h>

#include <set>
#include <sstream>

namespace aidl::android::os {

/**
 * Wrapper class that enables interop with AIDL NDK generation
 * Takes ownership of the APersistableBundle* given to it in reset() and will automatically
 * destroy it in the destructor, similar to a smart pointer container
 */
class PersistableBundle {
   public:
    PersistableBundle() noexcept : mPBundle(APersistableBundle_new()) {}
    // takes ownership of the APersistableBundle*
    PersistableBundle(APersistableBundle* _Nonnull bundle) noexcept : mPBundle(bundle) {}
    // takes ownership of the APersistableBundle*
    PersistableBundle(PersistableBundle&& other) noexcept : mPBundle(other.release()) {}
    // duplicates, does not take ownership of the APersistableBundle*
    PersistableBundle(const PersistableBundle& other) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            mPBundle = APersistableBundle_dup(other.mPBundle);
        }
    }
    // duplicates, does not take ownership of the APersistableBundle*
    PersistableBundle& operator=(const PersistableBundle& other) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            mPBundle = APersistableBundle_dup(other.mPBundle);
        }
        return *this;
    }

    ~PersistableBundle() { reset(); }

    binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
        reset();
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_readFromParcel(parcel, &mPBundle);
        } else {
            return STATUS_FAILED_TRANSACTION;
        }
    }

    binder_status_t writeToParcel(AParcel* _Nonnull parcel) const {
        if (!mPBundle) {
            return STATUS_BAD_VALUE;
        }
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_writeToParcel(mPBundle, parcel);
        } else {
            return STATUS_FAILED_TRANSACTION;
        }
    }

    /**
     * Destroys any currently owned APersistableBundle* and takes ownership of the given
     * APersistableBundle*
     *
     * @param pBundle The APersistableBundle to take ownership of
     */
    void reset(APersistableBundle* _Nullable pBundle = nullptr) noexcept {
        if (mPBundle) {
            if (__builtin_available(android __ANDROID_API_V__, *)) {
                APersistableBundle_delete(mPBundle);
            }
            mPBundle = nullptr;
        }
        mPBundle = pBundle;
    }

    /**
     * Check the actual contents of the bundle for equality. This is typically
     * what should be used to check for equality.
     */
    bool deepEquals(const PersistableBundle& rhs) const {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_isEqual(get(), rhs.get());
        } else {
            return false;
        }
    }

    /**
     * NOTE: This does NOT check the contents of the PersistableBundle. This is
     * implemented for ordering. Use deepEquals() to check for equality between
     * two different PersistableBundle objects.
     */
    inline bool operator==(const PersistableBundle& rhs) const { return get() == rhs.get(); }
    inline bool operator!=(const PersistableBundle& rhs) const { return get() != rhs.get(); }

    inline bool operator<(const PersistableBundle& rhs) const { return get() < rhs.get(); }
    inline bool operator>(const PersistableBundle& rhs) const { return get() > rhs.get(); }
    inline bool operator>=(const PersistableBundle& rhs) const { return !(*this < rhs); }
    inline bool operator<=(const PersistableBundle& rhs) const { return !(*this > rhs); }

    PersistableBundle& operator=(PersistableBundle&& other) noexcept {
        reset(other.release());
        return *this;
    }

    /**
     * Stops managing any contained APersistableBundle*, returning it to the caller. Ownership
     * is released.
     * @return APersistableBundle* or null if this was empty
     */
    [[nodiscard]] APersistableBundle* _Nullable release() noexcept {
        APersistableBundle* _Nullable ret = mPBundle;
        mPBundle = nullptr;
        return ret;
    }

    inline std::string toString() const {
        if (!mPBundle) {
            return "<PersistableBundle: null>";
        } else if (__builtin_available(android __ANDROID_API_V__, *)) {
            std::ostringstream os;
            os << "<PersistableBundle: ";
            os << "size: " << std::to_string(APersistableBundle_size(mPBundle));
            os << " >";
            return os.str();
        }
        return "<PersistableBundle (unknown)>";
    }

    int32_t size() const {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_size(mPBundle);
        } else {
            return 0;
        }
    }

    int32_t erase(const std::string& key) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_erase(mPBundle, key.c_str());
        } else {
            return 0;
        }
    }

    void putBoolean(const std::string& key, bool val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            APersistableBundle_putBoolean(mPBundle, key.c_str(), val);
        }
    }

    void putInt(const std::string& key, int32_t val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            APersistableBundle_putInt(mPBundle, key.c_str(), val);
        }
    }

    void putLong(const std::string& key, int64_t val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            APersistableBundle_putLong(mPBundle, key.c_str(), val);
        }
    }

    void putDouble(const std::string& key, double val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            APersistableBundle_putDouble(mPBundle, key.c_str(), val);
        }
    }

    void putString(const std::string& key, const std::string& val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            APersistableBundle_putString(mPBundle, key.c_str(), val.c_str());
        }
    }

    void putBooleanVector(const std::string& key, const std::vector<bool>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            // std::vector<bool> has no ::data().
            int32_t num = vec.size();
            if (num > 0) {
                bool* newVec = (bool*)malloc(num * sizeof(bool));
                if (newVec) {
                    for (int32_t i = 0; i < num; i++) {
                        newVec[i] = vec[i];
                    }
                    APersistableBundle_putBooleanVector(mPBundle, key.c_str(), newVec, num);
                    free(newVec);
                }
            }
        }
    }

    void putIntVector(const std::string& key, const std::vector<int32_t>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            int32_t num = vec.size();
            if (num > 0) {
                APersistableBundle_putIntVector(mPBundle, key.c_str(), vec.data(), num);
            }
        }
    }
    void putLongVector(const std::string& key, const std::vector<int64_t>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            int32_t num = vec.size();
            if (num > 0) {
                APersistableBundle_putLongVector(mPBundle, key.c_str(), vec.data(), num);
            }
        }
    }
    void putDoubleVector(const std::string& key, const std::vector<double>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            int32_t num = vec.size();
            if (num > 0) {
                APersistableBundle_putDoubleVector(mPBundle, key.c_str(), vec.data(), num);
            }
        }
    }
    void putStringVector(const std::string& key, const std::vector<std::string>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            int32_t num = vec.size();
            if (num > 0) {
                char** inVec = (char**)malloc(num * sizeof(char*));
                if (inVec) {
                    for (int32_t i = 0; i < num; i++) {
                        inVec[i] = strdup(vec[i].c_str());
                    }
                    APersistableBundle_putStringVector(mPBundle, key.c_str(), inVec, num);
                    free(inVec);
                }
            }
        }
    }
    void putPersistableBundle(const std::string& key, const PersistableBundle& pBundle) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            APersistableBundle_putPersistableBundle(mPBundle, key.c_str(), pBundle.mPBundle);
        }
    }

    bool getBoolean(const std::string& key, bool* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_getBoolean(mPBundle, key.c_str(), val);
        } else {
            return false;
        }
    }

    bool getInt(const std::string& key, int32_t* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_getInt(mPBundle, key.c_str(), val);
        } else {
            return false;
        }
    }

    bool getLong(const std::string& key, int64_t* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_getLong(mPBundle, key.c_str(), val);
        } else {
            return false;
        }
    }

    bool getDouble(const std::string& key, double* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return APersistableBundle_getDouble(mPBundle, key.c_str(), val);
        } else {
            return false;
        }
    }

    static char* _Nullable stringAllocator(int32_t bufferSizeBytes, void* _Nullable) {
        return (char*)malloc(bufferSizeBytes);
    }

    bool getString(const std::string& key, std::string* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            char* outString = nullptr;
            bool ret = APersistableBundle_getString(mPBundle, key.c_str(), &outString,
                                                    &stringAllocator, nullptr);
            if (ret && outString) {
                *val = std::string(outString);
            }
            return ret;
        } else {
            return false;
        }
    }

    template <typename T>
    bool getVecInternal(int32_t (*_Nonnull getVec)(const APersistableBundle* _Nonnull,
                                                   const char* _Nonnull, T* _Nullable, int32_t),
                        const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
                        std::vector<T>* _Nonnull vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            int32_t bytes = 0;
            // call first with nullptr to get required size in bytes
            bytes = getVec(pBundle, key, nullptr, 0);
            if (bytes > 0) {
                T* newVec = (T*)malloc(bytes);
                if (newVec) {
                    bytes = getVec(pBundle, key, newVec, bytes);
                    int32_t elements = bytes / sizeof(T);
                    vec->clear();
                    for (int32_t i = 0; i < elements; i++) {
                        vec->push_back(newVec[i]);
                    }
                    free(newVec);
                    return true;
                }
            }
        }
        return false;
    }

    bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) {
        return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(),
                                    vec);
    }
    bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) {
        return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(),
                                       vec);
    }
    bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) {
        return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(),
                                       vec);
    }
    bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) {
        return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle, key.c_str(),
                                      vec);
    }

    // Takes ownership of and frees the char** and its elements.
    // Creates a new set or vector based on the array of char*.
    template <typename T>
    T moveStringsInternal(char* _Nullable* _Nonnull strings, int32_t bufferSizeBytes) {
        if (strings && bufferSizeBytes > 0) {
            int32_t num = bufferSizeBytes / sizeof(char*);
            T ret;
            for (int32_t i = 0; i < num; i++) {
                ret.insert(ret.end(), std::string(strings[i]));
                free(strings[i]);
            }
            free(strings);
            return ret;
        }
        return T();
    }

    bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) {
        int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0,
                                                           &stringAllocator, nullptr);
        if (bytes > 0) {
            char** strings = (char**)malloc(bytes);
            if (strings) {
                bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), strings, bytes,
                                                           &stringAllocator, nullptr);
                *vec = moveStringsInternal<std::vector<std::string>>(strings, bytes);
                return true;
            }
        }
        return false;
    }

    bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            APersistableBundle* bundle = nullptr;
            bool ret = APersistableBundle_getPersistableBundle(mPBundle, key.c_str(), &bundle);
            if (ret) {
                *val = PersistableBundle(bundle);
            }
            return ret;
        } else {
            return false;
        }
    }

    std::set<std::string> getKeys(
            int32_t (*_Nonnull getTypedKeys)(const APersistableBundle* _Nonnull pBundle,
                                             char* _Nullable* _Nullable outKeys,
                                             int32_t bufferSizeBytes,
                                             APersistableBundle_stringAllocator stringAllocator,
                                             void* _Nullable),
            const APersistableBundle* _Nonnull pBundle) {
        // call first with nullptr to get required size in bytes
        int32_t bytes = getTypedKeys(pBundle, nullptr, 0, &stringAllocator, nullptr);
        if (bytes > 0) {
            char** keys = (char**)malloc(bytes);
            if (keys) {
                bytes = getTypedKeys(pBundle, keys, bytes, &stringAllocator, nullptr);
                return moveStringsInternal<std::set<std::string>>(keys, bytes);
            }
        }
        return {};
    }

    std::set<std::string> getBooleanKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getBooleanKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getIntKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getIntKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getLongKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getLongKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getDoubleKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getDoubleKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getStringKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getStringKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getBooleanVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getBooleanVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getIntVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getIntVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getLongVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getLongVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getDoubleVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getDoubleVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getStringVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getStringVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getPersistableBundleKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
            return getKeys(&APersistableBundle_getPersistableBundleKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getMonKeys() {
        // :P
        return {"c(o,o)b", "c(o,o)b"};
    }

   private:
    inline APersistableBundle* _Nullable get() const { return mPBundle; }
    APersistableBundle* _Nullable mPBundle = nullptr;
};

}  // namespace aidl::android::os
+905 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading