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

Commit c23be504 authored by Atneya Nair's avatar Atneya Nair
Browse files

Add permission caching to PermissionController

Audioserver currently calls upwards to system_server for all permission
checks.

Invert the call direction, and maintain mapping of uids which hold a
particular permission. Add AIDL interface for system_server and enum
representing relevant permissions.

Test: atest audiopermissioncontroller_test
Bug: 338089555
Flag: com.android.media.audio.audioserver_permissions
Change-Id: I45be63217fa58544e6dd9530a5d9e29b99f31ade
parent 85a07e23
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.media.permission;

import com.android.media.permission.PermissionEnum;
import com.android.media.permission.UidPackageState;

/**
@@ -33,4 +34,13 @@ interface INativePermissionController {
     * If the list is empty, the package no longer exists.
     */
    void updatePackagesForUid(in UidPackageState newPackageState);
    /**
     * Populate or replace the list of uids which holds a particular permission.
     * Runtime permissions will need additional checks, and should not use the cache as-is.
     * Not virtual device aware.
     * Is is possible for updates to the permission state to be delayed during high traffic.
     * @param perm - Enum representing the permission for which holders are being supplied
     * @param uids - Uids (not app-ids) which hold the permission. Should be sorted
     */
    void populatePermissionState(in PermissionEnum perm, in int[] uids);
}
+31 −0
Original line number Diff line number Diff line
/*
 * 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 com.android.media.permission;

/**
 * Enumerates permissions which are tracked/pushed by NativePermissionController
 * {@hide}
 */
enum PermissionEnum {
    MODIFY_AUDIO_ROUTING = 0,
    MODIFY_PHONE_STATE = 1,
    CALL_AUDIO_INTERCEPTION = 2,
    // This is a runtime + WIU permission, which means data delivery should be protected by AppOps
    // We query the controller only for early fails/hard errors
    RECORD_AUDIO = 3,
    ENUM_SIZE = 4, // Not for actual usage
}
+24 −0
Original line number Diff line number Diff line
@@ -88,6 +88,19 @@ Status NativePermissionController::updatePackagesForUid(const UidPackageState& n
    return Status::ok();
}

Status NativePermissionController::populatePermissionState(PermissionEnum perm,
                                                           const std::vector<int>& uids) {
    if (perm >= PermissionEnum::ENUM_SIZE || static_cast<int>(perm) < 0) {
        return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
    }
    std::lock_guard l{m_};
    auto& cursor = permission_map_[static_cast<size_t>(perm)];
    cursor = std::vector<uid_t>{uids.begin(), uids.end()};
    // should be sorted
    std::sort(cursor.begin(), cursor.end());
    return Status::ok();
}

// -- End Binder methods

Result<std::vector<std::string>> NativePermissionController::getPackagesForUid(uid_t uid) const {
@@ -120,4 +133,15 @@ Result<bool> NativePermissionController::validateUidPackagePair(
           (std::find(cursor->second.begin(), cursor->second.end(), packageName) !=
            cursor->second.end());
}

Result<bool> NativePermissionController::checkPermission(PermissionEnum perm, uid_t uid) const {
    std::lock_guard l{m_};
    const auto& uids = permission_map_[static_cast<size_t>(perm)];
    if (!uids.empty()) {
        return std::binary_search(uids.begin(), uids.end(), uid);
    } else {
        return unexpected{::android::NO_INIT};
    }
}

}  // namespace com::android::media::permission
+6 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <optional>
#include <vector>

#include <com/android/media/permission/PermissionEnum.h>
#include <error/Result.h>

namespace com::android::media::permission {
@@ -38,6 +39,11 @@ class IPermissionProvider {
    // Fails if the provider does not know about the app-id.
    virtual ::android::error::Result<bool> validateUidPackagePair(
            uid_t uid, const std::string& packageName) const = 0;

    // True iff the uid holds the permission (user aware).
    // Fails with NO_INIT if cache hasn't been populated.
    virtual ::android::error::Result<bool> checkPermission(PermissionEnum permission,
                                                           uid_t uid) const = 0;
    virtual ~IPermissionProvider() = default;
};
}  // namespace com::android::media::permission
+6 −0
Original line number Diff line number Diff line
@@ -33,16 +33,22 @@ class NativePermissionController : public BnNativePermissionController, public I
  public:
    Status populatePackagesForUids(const std::vector<UidPackageState>& initialPackageStates) final;
    Status updatePackagesForUid(const UidPackageState& newPackageState) final;
    Status populatePermissionState(PermissionEnum permission, const std::vector<int>& uids) final;
    // end binder methods

    ::android::error::Result<std::vector<std::string>> getPackagesForUid(uid_t uid) const final;
    ::android::error::Result<bool> validateUidPackagePair(
            uid_t uid, const std::string& packageName) const final;
    ::android::error::Result<bool> checkPermission(PermissionEnum permission,
                                                   uid_t uid) const final;

  private:
    mutable std::mutex m_;
    // map of app_ids to the set of packages names which could run in them (should be 1)
    std::unordered_map<uid_t, std::vector<std::string>> package_map_ GUARDED_BY(m_);
    bool is_package_populated_ GUARDED_BY(m_);
    // (logical) map of PermissionEnum to list of uids (not appid) which hold the perm
    std::array<std::vector<uid_t>, static_cast<size_t>(PermissionEnum::ENUM_SIZE)> permission_map_
            GUARDED_BY(m_);
};
}  // namespace com::android::media::permission
Loading