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

Commit 6267b539 authored by Ruben Brunk's avatar Ruben Brunk
Browse files

camera2: Fix work-profile eviction handling.

Bug: 20124384
Change-Id: I6fb82dbfd5f98746ed4befed81a583e3709bfee8
parent 51c834c8
Loading
Loading
Loading
Loading
+23 −5
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <utils/Errors.h>
#include <utils/String16.h>

#include <inttypes.h>
#include <stdint.h>
#include <sys/types.h>

@@ -303,10 +304,10 @@ public:
        return res;
    }

    virtual void notifySystemEvent(int eventId, int arg0) {
    virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t len) {
        Parcel data, reply;
        data.writeInt32(eventId);
        data.writeInt32(arg0);
        data.writeInt32Array(len, args);
        remote()->transact(BnCameraService::NOTIFY_SYSTEM_EVENT, data, &reply,
                IBinder::FLAG_ONEWAY);
    }
@@ -481,9 +482,26 @@ status_t BnCameraService::onTransact(
        } break;
        case NOTIFY_SYSTEM_EVENT: {
            CHECK_INTERFACE(ICameraService, data, reply);
            int eventId = data.readInt32();
            int arg0 = data.readInt32();
            notifySystemEvent(eventId, arg0);
            int32_t eventId = data.readInt32();
            int32_t len = data.readInt32();
            if (len < 0) {
                ALOGE("%s: Received poorly formatted length in binder request: notifySystemEvent.",
                        __FUNCTION__);
                return FAILED_TRANSACTION;
            }
            if (len > 512) {
                ALOGE("%s: Length %" PRIi32 " too long in binder request: notifySystemEvent.",
                        __FUNCTION__, len);
                return FAILED_TRANSACTION;
            }
            int32_t events[len] = {};
            status_t status = data.read(events, sizeof(int32_t) * len);
            if (status != NO_ERROR) {
                ALOGE("%s: Received poorly formatted binder request: notifySystemEvent.",
                        __FUNCTION__);
                return FAILED_TRANSACTION;
            }
            notifySystemEvent(eventId, events, len);
            return NO_ERROR;
        } break;
        default:
+1 −1
Original line number Diff line number Diff line
@@ -164,7 +164,7 @@ public:
    /**
     * Notify the camera service of a system event.  Should only be called from system_server.
     */
    virtual void notifySystemEvent(int eventId, int arg0) = 0;
    virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) = 0;
};

// ----------------------------------------------------------------------------
+64 −19
Original line number Diff line number Diff line
@@ -122,8 +122,8 @@ static void torch_mode_status_change(
// should be ok for now.
static CameraService *gCameraService;

CameraService::CameraService() : mEventLog(DEFAULT_EVENT_LOG_LENGTH),
        mLastUserId(DEFAULT_LAST_USER_ID), mSoundRef(0), mModule(0), mFlashlight(0) {
CameraService::CameraService() : mEventLog(DEFAULT_EVENT_LOG_LENGTH), mAllowedUsers(),
        mSoundRef(0), mModule(0), mFlashlight(0) {
    ALOGI("CameraService started (pid=%d)", getpid());
    gCameraService = this;

@@ -676,6 +676,20 @@ status_t CameraService::makeClient(const sp<CameraService>& cameraService,
    return NO_ERROR;
}

String8 CameraService::toString(std::set<userid_t> intSet) {
    String8 s("");
    bool first = true;
    for (userid_t i : intSet) {
        if (first) {
            s.appendFormat("%d", i);
            first = false;
        } else {
            s.appendFormat(", %d", i);
        }
    }
    return s;
}

status_t CameraService::initializeShimMetadata(int cameraId) {
    int uid = getCallingUid();

@@ -783,7 +797,7 @@ status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/
    // Check device policy for this camera
    char value[PROPERTY_VALUE_MAX];
    char key[PROPERTY_KEY_MAX];
    int clientUserId = multiuser_get_user_id(clientUid);
    userid_t clientUserId = multiuser_get_user_id(clientUid);
    snprintf(key, PROPERTY_KEY_MAX, "sys.secpolicy.camera.off_%d", clientUserId);
    property_get(key, value, "0");
    if (strcmp(value, "1") == 0) {
@@ -795,10 +809,10 @@ status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/

    // Only allow clients who are being used by the current foreground device user, unless calling
    // from our own process.
    if (callingPid != getpid() &&
            (mLastUserId != clientUserId && mLastUserId != DEFAULT_LAST_USER_ID)) {
        ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from previous "
                "device user %d, current device user %d)", callingPid, clientUserId, mLastUserId);
    if (callingPid != getpid() && (mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) {
        ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from "
                "device user %d, currently allowed device users: %s)", callingPid, clientUserId,
                toString(mAllowedUsers).string());
        return PERMISSION_DENIED;
    }

@@ -1197,10 +1211,10 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
    return OK;
}

void CameraService::notifySystemEvent(int eventId, int arg0) {
void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) {
    switch(eventId) {
        case ICameraService::USER_SWITCHED: {
            doUserSwitch(/*newUserId*/arg0);
            doUserSwitch(/*newUserIds*/args, /*length*/length);
            break;
        }
        case ICameraService::NO_EVENT:
@@ -1443,20 +1457,30 @@ sp<CameraService::BasicClient> CameraService::removeClientLocked(const String8&
    return clientDescriptorPtr->getValue();
}

void CameraService::doUserSwitch(int newUserId) {
void CameraService::doUserSwitch(const int32_t* newUserId, size_t length) {
    // Acquire mServiceLock and prevent other clients from connecting
    std::unique_ptr<AutoConditionLock> lock =
            AutoConditionLock::waitAndAcquire(mServiceLockWrapper);

    if (newUserId <= 0) {
        ALOGW("%s: Bad user ID %d given during user switch, resetting to default.", __FUNCTION__,
                newUserId);
        newUserId = DEFAULT_LAST_USER_ID;
    std::set<userid_t> newAllowedUsers;
    for (size_t i = 0; i < length; i++) {
        if (newUserId[i] < 0) {
            ALOGE("%s: Bad user ID %d given during user switch, ignoring.",
                    __FUNCTION__, newUserId[i]);
            return;
        }
        newAllowedUsers.insert(static_cast<userid_t>(newUserId[i]));
    }


    if (newAllowedUsers == mAllowedUsers) {
        ALOGW("%s: Received notification of user switch with no updated user IDs.", __FUNCTION__);
        return;
    }

    logUserSwitch(mLastUserId, newUserId);
    logUserSwitch(mAllowedUsers, newAllowedUsers);

    mLastUserId = newUserId;
    mAllowedUsers = std::move(newAllowedUsers);

    // Current user has switched, evict all current clients.
    std::vector<sp<BasicClient>> evicted;
@@ -1468,6 +1492,13 @@ void CameraService::doUserSwitch(int newUserId) {
            continue;
        }

        // Don't evict clients that are still allowed.
        uid_t clientUid = clientSp->getClientUid();
        userid_t clientUserId = multiuser_get_user_id(clientUid);
        if (mAllowedUsers.find(clientUserId) != mAllowedUsers.end()) {
            continue;
        }

        evicted.push_back(clientSp);

        String8 curTime = getFormattedCurrentTime();
@@ -1527,10 +1558,13 @@ void CameraService::logRejected(const char* cameraId, int clientPid,
            cameraId, clientPackage, clientPid, reason));
}

void CameraService::logUserSwitch(int oldUserId, int newUserId) {
void CameraService::logUserSwitch(const std::set<userid_t>& oldUserIds,
        const std::set<userid_t>& newUserIds) {
    String8 newUsers = toString(newUserIds);
    String8 oldUsers = toString(oldUserIds);
    // Log the new and old users
    logEvent(String8::format("USER_SWITCH from old user: %d , to new user: %d", oldUserId,
            newUserId));
    logEvent(String8::format("USER_SWITCH previous allowed users: %s , current allowed users: %s",
            oldUsers.string(), newUsers.string()));
}

void CameraService::logDeviceRemoved(const char* cameraId, const char* reason) {
@@ -1735,6 +1769,10 @@ int CameraService::BasicClient::getClientPid() const {
    return mClientPid;
}

uid_t CameraService::BasicClient::getClientUid() const {
    return mClientUid;
}

bool CameraService::BasicClient::canCastToApiClient(apiLevel level) const {
    // Defaults to API2.
    return level == API_2;
@@ -1937,12 +1975,18 @@ String8 CameraService::CameraClientManager::toString() const {
        auto conflicting = i->getConflicting();
        auto clientSp = i->getValue();
        String8 packageName;
        userid_t clientUserId;
        if (clientSp.get() != nullptr) {
            packageName = String8{clientSp->getPackageName()};
            uid_t clientUid = clientSp->getClientUid();
            clientUserId = multiuser_get_user_id(clientUid);
        }
        ret.appendFormat("\n(Camera ID: %s, Cost: %" PRId32 ", PID: %" PRId32 ", Priority: %"
                PRId32 ", ", key.string(), cost, pid, priority);

        if (clientSp.get() != nullptr) {
            ret.appendFormat("User Id: %d, ", clientUserId);
        }
        if (packageName.size() != 0) {
            ret.appendFormat("Client Package Name: %s", packageName.string());
        }
@@ -2025,6 +2069,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
        result.appendFormat("Number of camera devices: %d\n", mNumberOfCameras);
        String8 activeClientString = mActiveClientManager.toString();
        result.appendFormat("Active Camera Clients:\n%s", activeClientString.string());
        result.appendFormat("Allowed users:\n%s\n", toString(mAllowedUsers).string());

        sp<VendorTagDescriptor> desc = VendorTagDescriptor::getGlobalVendorTagDescriptor();
        if (desc == NULL) {
+14 −20
Original line number Diff line number Diff line
@@ -83,11 +83,6 @@ public:
    // Default number of messages to store in eviction log
    static const size_t DEFAULT_EVENT_LOG_LENGTH = 100;

    enum {
        // Default last user id
        DEFAULT_LAST_USER_ID = 0,
    };

    // Implementation of BinderService<T>
    static char const* getServiceName() { return "media.camera"; }

@@ -141,7 +136,7 @@ public:
    virtual status_t    setTorchMode(const String16& cameraId, bool enabled,
            const sp<IBinder>& clientBinder);

    virtual void notifySystemEvent(int eventId, int arg0);
    virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t length);

    // OK = supports api of that version, -EOPNOTSUPP = does not support
    virtual status_t    supportsCameraApi(
@@ -200,6 +195,9 @@ public:
        virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
                const CaptureResultExtras& resultExtras) = 0;

        // Get the UID of the application client using this
        virtual uid_t getClientUid() const;

        // Get the PID of the application client using this
        virtual int getClientPid() const;

@@ -469,7 +467,6 @@ private:
            const String16& clientPackageName, int clientUid, apiLevel effectiveApiLevel,
            bool legacyMode, bool shimUpdateOnly, /*out*/sp<CLIENT>& device);


    // Lock guarding camera service state
    Mutex               mServiceLock;

@@ -492,8 +489,8 @@ private:
    RingBuffer<String8> mEventLog;
    Mutex mLogLock;

    // UID of last user.
    int mLastUserId;
    // Currently allowed user IDs
    std::set<userid_t> mAllowedUsers;

    /**
     * Get the camera state for a given camera id.
@@ -542,7 +539,7 @@ private:
    /**
     * Handle a notification that the current device user has changed.
     */
    void doUserSwitch(int newUserId);
    void doUserSwitch(const int32_t* newUserId, size_t length);

    /**
     * Add an event log message.
@@ -568,7 +565,8 @@ private:
    /**
     * Add an event log message that the current device user has been switched.
     */
    void logUserSwitch(int oldUserId, int newUserId);
    void logUserSwitch(const std::set<userid_t>& oldUserIds,
        const std::set<userid_t>& newUserIds);

    /**
     * Add an event log message that a device has been removed by the HAL
@@ -699,6 +697,11 @@ private:
            int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
            int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
            /*out*/sp<BasicClient>* client);

    status_t checkCameraAccess(const String16& opPackageName);

    static String8 toString(std::set<userid_t> intSet);

};

template<class Func>
@@ -775,15 +778,6 @@ status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String
        if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
            return ret;
        }
        int userId = multiuser_get_user_id(clientUid);

        if (userId != mLastUserId && clientPid != getpid() ) {
            // If no previous user ID had been set, set to the user of the caller.
            logUserSwitch(mLastUserId, userId);
            LOG_ALWAYS_FATAL_IF(mLastUserId != DEFAULT_LAST_USER_ID,
                    "Invalid state: Should never update user ID here unless was default");
            mLastUserId = userId;
        }

        // Check the shim parameters after acquiring lock, if they have already been updated and
        // we were doing a shim update, return immediately