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

Commit bf6a5836 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "No camera for idle uids - av framework"

parents 4173ed39 a453d0d2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ interface ICameraDeviceCallbacks
    const int ERROR_CAMERA_REQUEST = 3;
    const int ERROR_CAMERA_RESULT = 4;
    const int ERROR_CAMERA_BUFFER = 5;
    const int ERROR_CAMERA_DISABLED = 6;

    oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
    oneway void onDeviceIdle();
+235 −6
Original line number Diff line number Diff line
@@ -33,14 +33,18 @@

#include <android-base/macros.h>
#include <android-base/parseint.h>
#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <binder/PermissionController.h>
#include <binder/ProcessInfoService.h>
#include <binder/IResultReceiver.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
#include <cutils/misc.h>
#include <gui/Surface.h>
#include <hardware/hardware.h>
#include <memunreachable/memunreachable.h>
@@ -165,6 +169,8 @@ static void torch_mode_status_change(

// ----------------------------------------------------------------------------

static const String16 sManageCameraPermission("android.permission.MANAGE_CAMERA");

CameraService::CameraService() :
        mEventLog(DEFAULT_EVENT_LOG_LENGTH),
        mNumberOfCameras(0), mNumberOfNormalCameras(0),
@@ -196,6 +202,9 @@ void CameraService::onFirstRef()
    }

    CameraService::pingCameraServiceProxy();

    mUidPolicy = new UidPolicy(this);
    mUidPolicy->registerSelf();
}

status_t CameraService::enumerateProviders() {
@@ -275,6 +284,7 @@ void CameraService::pingCameraServiceProxy() {

CameraService::~CameraService() {
    VendorTagDescriptor::clearGlobalVendorTagDescriptor();
    mUidPolicy->unregisterSelf();
}

void CameraService::onNewProviderRegistered() {
@@ -933,6 +943,15 @@ Status CameraService::validateClientPermissionsLocked(const String8& cameraId,
                clientName8.string(), clientUid, clientPid, cameraId.string());
    }

    // Make sure the UID is in an active state to use the camera
    if (!mUidPolicy->isUidActive(callingUid)) {
        ALOGE("Access Denial: can't use the camera from an idle UID pid=%d, uid=%d",
            clientPid, clientUid);
        return STATUS_ERROR_FMT(ERROR_DISABLED,
                "Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" from background",
                clientName8.string(), clientUid, clientPid, cameraId.string());
    }

    // Only use passed in clientPid to check permission. Use calling PID as the client PID that's
    // connected to camera service directly.
    originalClientPid = clientPid;
@@ -1969,6 +1988,30 @@ status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* re

    // Permission checks
    switch (code) {
        case SHELL_COMMAND_TRANSACTION: {
            int in = data.readFileDescriptor();
            int out = data.readFileDescriptor();
            int err = data.readFileDescriptor();
            int argc = data.readInt32();
            Vector<String16> args;
            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
               args.add(data.readString16());
            }
            sp<IBinder> unusedCallback;
            sp<IResultReceiver> resultReceiver;
            status_t status;
            if ((status = data.readNullableStrongBinder(&unusedCallback)) != NO_ERROR) {
                return status;
            }
            if ((status = data.readNullableStrongBinder(&resultReceiver)) != NO_ERROR) {
                return status;
            }
            status = shellCommand(in, out, err, args);
            if (resultReceiver != nullptr) {
                resultReceiver->send(status);
            }
            return NO_ERROR;
        }
        case BnCameraService::NOTIFYSYSTEMEVENT: {
            if (pid != selfPid) {
                // Ensure we're being called by system_server, or similar process with
@@ -2286,14 +2329,20 @@ void CameraService::BasicClient::opChanged(int32_t op, const String16& packageNa
    if (res != AppOpsManager::MODE_ALLOWED) {
        ALOGI("Camera %s: Access for \"%s\" revoked", mCameraIdStr.string(),
                myName.string());
        block();
    }
}

void CameraService::BasicClient::block() {
    ATRACE_CALL();

    // Reset the client PID to allow server-initiated disconnect,
    // and to prevent further calls by client.
    mClientPid = getCallingPid();
    CaptureResultExtras resultExtras; // a dummy result (invalid)
        notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE, resultExtras);
    notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISABLED, resultExtras);
    disconnect();
}
}

// ----------------------------------------------------------------------------

@@ -2330,6 +2379,98 @@ void CameraService::Client::OpsCallback::opChanged(int32_t op,
    }
}

// ----------------------------------------------------------------------------
//                  UidPolicy
// ----------------------------------------------------------------------------

void CameraService::UidPolicy::registerSelf() {
    ActivityManager am;
    am.registerUidObserver(this, ActivityManager::UID_OBSERVER_GONE
            | ActivityManager::UID_OBSERVER_IDLE
            | ActivityManager::UID_OBSERVER_ACTIVE,
            ActivityManager::PROCESS_STATE_UNKNOWN,
            String16("cameraserver"));
}

void CameraService::UidPolicy::unregisterSelf() {
    ActivityManager am;
    am.unregisterUidObserver(this);
}

void CameraService::UidPolicy::onUidGone(uid_t uid, bool disabled) {
    onUidIdle(uid, disabled);
}

void CameraService::UidPolicy::onUidActive(uid_t uid) {
    Mutex::Autolock _l(mUidLock);
    mActiveUids.insert(uid);
}

void CameraService::UidPolicy::onUidIdle(uid_t uid, bool /* disabled */) {
    bool deleted = false;
    {
        Mutex::Autolock _l(mUidLock);
        if (mActiveUids.erase(uid) > 0) {
            deleted = true;
        }
    }
    if (deleted) {
        sp<CameraService> service = mService.promote();
        if (service != nullptr) {
            service->blockClientsForUid(uid);
        }
    }
}

bool CameraService::UidPolicy::isUidActive(uid_t uid) {
    // Non-app UIDs are considered always active
    if (uid < FIRST_APPLICATION_UID) {
        return true;
    }
    Mutex::Autolock _l(mUidLock);
    return isUidActiveLocked(uid);
}

bool CameraService::UidPolicy::isUidActiveLocked(uid_t uid) {
    // Non-app UIDs are considered always active
    if (uid < FIRST_APPLICATION_UID) {
        return true;
    }
    auto it = mOverrideUids.find(uid);
    if (it != mOverrideUids.end()) {
        return it->second;
    }
    return mActiveUids.find(uid) != mActiveUids.end();
}

void CameraService::UidPolicy::UidPolicy::addOverrideUid(uid_t uid, bool active) {
    updateOverrideUid(uid, active, true);
}

void CameraService::UidPolicy::removeOverrideUid(uid_t uid) {
    updateOverrideUid(uid, false, false);
}

void CameraService::UidPolicy::updateOverrideUid(uid_t uid, bool active, bool insert) {
    bool wasActive = false;
    bool isActive = false;
    {
        Mutex::Autolock _l(mUidLock);
        wasActive = isUidActiveLocked(uid);
        mOverrideUids.erase(uid);
        if (insert) {
            mOverrideUids.insert(std::pair<uid_t, bool>(uid, active));
        }
        isActive = isUidActiveLocked(uid);
    }
    if (wasActive != isActive && !isActive) {
        sp<CameraService> service = mService.promote();
        if (service != nullptr) {
            service->blockClientsForUid(uid);
        }
    }
}

// ----------------------------------------------------------------------------
//                  CameraState
// ----------------------------------------------------------------------------
@@ -2791,4 +2932,92 @@ status_t CameraService::setTorchStatusLocked(const String8& cameraId,
    return OK;
}

void CameraService::blockClientsForUid(uid_t uid) {
    const auto clients = mActiveClientManager.getAll();
    for (auto& current : clients) {
        if (current != nullptr) {
            const auto basicClient = current->getValue();
            if (basicClient.get() != nullptr && basicClient->getClientUid() == uid) {
                basicClient->block();
            }
        }
    }
}

// NOTE: This is a remote API - make sure all args are validated
status_t CameraService::shellCommand(int in, int out, int err, const Vector<String16>& args) {
    if (!checkCallingPermission(sManageCameraPermission, nullptr, nullptr)) {
        return PERMISSION_DENIED;
    }
    if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
        return BAD_VALUE;
    }
    if (args.size() == 3 && args[0] == String16("set-uid-state")) {
        return handleSetUidState(args, err);
    } else if (args.size() == 2 && args[0] == String16("reset-uid-state")) {
        return handleResetUidState(args, err);
    } else if (args.size() == 2 && args[0] == String16("get-uid-state")) {
        return handleGetUidState(args, out, err);
    } else if (args.size() == 1 && args[0] == String16("help")) {
        printHelp(out);
        return NO_ERROR;
    }
    printHelp(err);
    return BAD_VALUE;
}

status_t CameraService::handleSetUidState(const Vector<String16>& args, int err) {
    PermissionController pc;
    int uid = pc.getPackageUid(args[1], 0);
    if (uid <= 0) {
        ALOGE("Unknown package: '%s'", String8(args[1]).string());
        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
        return BAD_VALUE;
    }
    bool active = false;
    if (args[2] == String16("active")) {
        active = true;
    } else if ((args[2] != String16("idle"))) {
        ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
        return BAD_VALUE;
    }
    mUidPolicy->addOverrideUid(uid, active);
    return NO_ERROR;
}

status_t CameraService::handleResetUidState(const Vector<String16>& args, int err) {
    PermissionController pc;
    int uid = pc.getPackageUid(args[1], 0);
    if (uid < 0) {
        ALOGE("Unknown package: '%s'", String8(args[1]).string());
        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
        return BAD_VALUE;
    }
    mUidPolicy->removeOverrideUid(uid);
    return NO_ERROR;
}

status_t CameraService::handleGetUidState(const Vector<String16>& args, int out, int err) {
    PermissionController pc;
    int uid = pc.getPackageUid(args[1], 0);
    if (uid <= 0) {
        ALOGE("Unknown package: '%s'", String8(args[1]).string());
        dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
        return BAD_VALUE;
    }
    if (mUidPolicy->isUidActive(uid)) {
        return dprintf(out, "active\n");
    } else {
        return dprintf(out, "idle\n");
    }
}

status_t CameraService::printHelp(int out) {
    return dprintf(out, "Camera service commands:\n"
        "  get-uid-state <PACKAGE> gets the uid state\n"
        "  set-uid-state <PACKAGE> <active|idle> overrides the uid state\n"
        "  reset-uid-state <PACKAGE> clears the uid state override\n"
        "  help print this message\n");
}

}; // namespace android
+54 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
#include <binder/IAppOpsCallback.h>
#include <binder/IUidObserver.h>
#include <hardware/camera.h>

#include <android/hardware/camera/common/1.0/types.h>
@@ -47,6 +48,8 @@
#include <map>
#include <memory>
#include <utility>
#include <unordered_map>
#include <unordered_set>

namespace android {

@@ -163,6 +166,8 @@ public:

    virtual status_t    dump(int fd, const Vector<String16>& args);

    virtual status_t    shellCommand(int in, int out, int err, const Vector<String16>& args);

    /////////////////////////////////////////////////////////////////////
    // Client functionality

@@ -233,6 +238,9 @@ public:
        // Check what API level is used for this client. This is used to determine which
        // superclass this can be cast to.
        virtual bool canCastToApiClient(apiLevel level) const;

        // Block the client form using the camera
        virtual void block();
    protected:
        BasicClient(const sp<CameraService>& cameraService,
                const sp<IBinder>& remoteCallback,
@@ -506,6 +514,37 @@ private:
        CameraParameters mShimParams;
    }; // class CameraState

    // Observer for UID lifecycle enforcing that UIDs in idle
    // state cannot use the camera to protect user privacy.
    class UidPolicy : public BnUidObserver {
    public:
        explicit UidPolicy(sp<CameraService> service)
                : mService(service) {}

        void registerSelf();
        void unregisterSelf();

        bool isUidActive(uid_t uid);

        void onUidGone(uid_t uid, bool disabled);
        void onUidActive(uid_t uid);
        void onUidIdle(uid_t uid, bool disabled);

        void addOverrideUid(uid_t uid, bool active);
        void removeOverrideUid(uid_t uid);

    private:
        bool isUidActiveLocked(uid_t uid);
        void updateOverrideUid(uid_t uid, bool active, bool insert);

        Mutex mUidLock;
        wp<CameraService> mService;
        std::unordered_set<uid_t> mActiveUids;
        std::unordered_map<uid_t, bool> mOverrideUids;
    }; // class UidPolicy

    sp<UidPolicy> mUidPolicy;

    // Delay-load the Camera HAL module
    virtual void onFirstRef();

@@ -755,6 +794,21 @@ private:
     */
    binder::Status      getLegacyParametersLazy(int cameraId, /*out*/CameraParameters* parameters);

    // Blocks all clients from the UID
    void blockClientsForUid(uid_t uid);

    // Overrides the UID state as if it is idle
    status_t handleSetUidState(const Vector<String16>& args, int err);

    // Clears the override for the UID state
    status_t handleResetUidState(const Vector<String16>& args, int err);

    // Gets the UID state
    status_t handleGetUidState(const Vector<String16>& args, int out, int err);

    // Prints the shell command help
    status_t printHelp(int out);

    static int getCallingPid();

    static int getCallingUid();