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

Commit 24d0661c authored by Avichal Rakesh's avatar Avichal Rakesh Committed by Android (Google) Code Review
Browse files

Merge changes I0931837f,Ia5ce13f6

* changes:
  Cache monitored tag dump for watched clients when disconnected.
  Add 'watch' command to CameraService
parents 091ee7a2 7fbc398b
Loading
Loading
Loading
Loading
+292 −5
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ static constexpr int32_t kVendorClientScore = resource_policy::PERCEPTIBLE_APP_A
static constexpr int32_t kVendorClientState = ActivityManager::PROCESS_STATE_PERSISTENT_UI;

const String8 CameraService::kOfflineDevice("offline-");
const String16 CameraService::kWatchAllClientsFlag("all");

// Set to keep track of logged service error events.
static std::set<String8> sServiceErrorEventSet;
@@ -1788,7 +1789,8 @@ Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8&
        LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
                __FUNCTION__);

        err = client->initialize(mCameraProviderManager, mMonitorTags);
        String8 monitorTags = isClientWatched(client.get()) ? mMonitorTags : String8("");
        err = client->initialize(mCameraProviderManager, monitorTags);
        if (err != OK) {
            ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
            // Errors could be from the HAL module open call or from AppOpsManager
@@ -1954,7 +1956,8 @@ status_t CameraService::addOfflineClient(String8 cameraId, sp<BasicClient> offli
            return BAD_VALUE;
        }

        auto err = offlineClient->initialize(mCameraProviderManager, mMonitorTags);
        String8 monitorTags = isClientWatched(offlineClient.get()) ? mMonitorTags : String8("");
        auto err = offlineClient->initialize(mCameraProviderManager, monitorTags);
        if (err != OK) {
            ALOGE("%s: Could not initialize offline client.", __FUNCTION__);
            return err;
@@ -2620,6 +2623,7 @@ void CameraService::removeByClient(const BasicClient* client) {
    for (auto& i : mActiveClientManager.getAll()) {
        auto clientSp = i->getValue();
        if (clientSp.get() == client) {
            cacheClientTagDumpIfNeeded(client->mCameraIdStr, clientSp.get());
            mActiveClientManager.remove(i);
        }
    }
@@ -2696,7 +2700,11 @@ sp<CameraService::BasicClient> CameraService::removeClientLocked(const String8&
        return sp<BasicClient>{nullptr};
    }

    return clientDescriptorPtr->getValue();
    sp<BasicClient> client = clientDescriptorPtr->getValue();
    if (client.get() != nullptr) {
        cacheClientTagDumpIfNeeded(clientDescriptorPtr->getKey(), client.get());
    }
    return client;
}

void CameraService::doUserSwitch(const std::vector<int32_t>& newUserIds) {
@@ -3115,6 +3123,21 @@ status_t CameraService::BasicClient::dump(int, const Vector<String16>&) {
    return OK;
}

status_t CameraService::BasicClient::startWatchingTags(const String8&, int) {
    // Can't watch tags directly, must go through CameraService::startWatchingTags
    return OK;
}

status_t CameraService::BasicClient::stopWatchingTags(int) {
    // Can't watch tags directly, must go through CameraService::stopWatchingTags
    return OK;
}

status_t CameraService::BasicClient::dumpWatchedEventsToVector(std::vector<std::string> &) {
    // Can't watch tags directly, must go through CameraService::dumpWatchedEventsToVector
    return OK;
}

String16 CameraService::BasicClient::getPackageName() const {
    return mClientPackageName;
}
@@ -4136,7 +4159,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {

    // Dump camera traces if there were any
    dprintf(fd, "\n");
    camera3::CameraTraces::dump(fd, args);
    camera3::CameraTraces::dump(fd);

    // Process dump arguments, if any
    int n = args.size();
@@ -4230,6 +4253,30 @@ void CameraService::dumpEventLog(int fd) {
    dprintf(fd, "\n");
}

void CameraService::cacheClientTagDumpIfNeeded(const char *cameraId, BasicClient* client) {
    Mutex::Autolock lock(mLogLock);
    if (!isClientWatchedLocked(client)) { return; }

    std::vector<std::string> dumpVector;
    client->dumpWatchedEventsToVector(dumpVector);

    if (dumpVector.empty()) { return; }

    std::string dumpString;
    size_t i = dumpVector.size();

    // Store the string in reverse order (latest last)
    while (i > 0) {
         i--;
         dumpString += cameraId;
         dumpString += ":";
         dumpString += dumpVector[i]; // implicitly ends with '\n'
    }

    const String16 &packageName = client->getPackageName();
    mWatchedClientsDumpCache[packageName] = dumpString;
}

void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) {
    Mutex::Autolock al(mTorchClientMapMutex);
    for (size_t i = 0; i < mTorchClientMap.size(); i++) {
@@ -4534,9 +4581,11 @@ status_t CameraService::shellCommand(int in, int out, int err, const Vector<Stri
        return handleGetImageDumpMask(out);
    } else if (args.size() >= 2 && args[0] == String16("set-camera-mute")) {
        return handleSetCameraMute(args);
    } else if (args.size() >= 2 && args[0] == String16("watch")) {
        return handleWatchCommand(args, out);
    } else if (args.size() == 1 && args[0] == String16("help")) {
        printHelp(out);
        return NO_ERROR;
        return OK;
    }
    printHelp(err);
    return BAD_VALUE;
@@ -4680,6 +4729,233 @@ status_t CameraService::handleSetCameraMute(const Vector<String16>& args) {
    return OK;
}

status_t CameraService::handleWatchCommand(const Vector<String16>& args, int outFd) {
    if (args.size() >= 3 && args[1] == String16("start")) {
        return startWatchingTags(args, outFd);
    } else if (args.size() == 2 && args[1] == String16("dump")) {
        return camera3::CameraTraces::dump(outFd);
    } else if (args.size() == 2 && args[1] == String16("stop")) {
        return stopWatchingTags(outFd);
    } else if (args.size() >= 2 && args[1] == String16("print")) {
        return printWatchedTags(args, outFd);
    }
    dprintf(outFd, "Camera service watch commands:\n"
                 "  start -m <comma_separated_tag_list> [-c <comma_separated_client_list>]\n"
                 "        starts watching the provided tags for clients with provided package\n"
                 "        recognizes tag shorthands like '3a'\n"
                 "        watches all clients if no client is passed, or if 'all' is listed\n"
                 "  dump dumps camera trace\n"
                 "  stop stops watching all tags\n"
                 "  print [-n <refresh_interval_ms>]\n"
                 "        prints the monitored information in real time\n"
                 "        Hit Ctrl+C to exit\n");
  return BAD_VALUE;
}

status_t CameraService::startWatchingTags(const Vector<String16> &args, int outFd) {
    Mutex::Autolock lock(mLogLock);
    size_t tagsIdx; // index of '-m'
    String16 tags("");
    for (tagsIdx = 2; tagsIdx < args.size() && args[tagsIdx] != String16("-m"); tagsIdx++);
    if (tagsIdx < args.size() - 1) {
        tags = args[tagsIdx + 1];
    } else {
        dprintf(outFd, "No tags provided.\n");
        return BAD_VALUE;
    }

    size_t clientsIdx; // index of '-c'
    String16 clients = kWatchAllClientsFlag; // watch all clients if no clients are provided
    for (clientsIdx = 2; clientsIdx < args.size() && args[clientsIdx] != String16("-c");
         clientsIdx++);
    if (clientsIdx < args.size() - 1) {
        clients = args[clientsIdx + 1];
    }
    parseClientsToWatchLocked(String8(clients));

    // track tags to initialize future clients with the monitoring information
    mMonitorTags = String8(tags);

    bool serviceLock = tryLock(mServiceLock);
    int numWatchedClients = 0;
    auto cameraClients = mActiveClientManager.getAll();
    for (const auto &clientDescriptor: cameraClients) {
        if (clientDescriptor == nullptr) { continue; }
        sp<BasicClient> client = clientDescriptor->getValue();
        if (client.get() == nullptr) { continue; }

        if (isClientWatchedLocked(client.get())) {
            client->startWatchingTags(mMonitorTags, outFd);
            numWatchedClients++;
        }
    }
    dprintf(outFd, "Started watching %d active clients\n", numWatchedClients);

    if (serviceLock) { mServiceLock.unlock(); }
    return OK;
}

status_t CameraService::stopWatchingTags(int outFd) {
    // clear mMonitorTags to prevent new clients from monitoring tags at initialization
    Mutex::Autolock lock(mLogLock);
    mMonitorTags = String8::empty();

    mWatchedClientPackages.clear();
    mWatchedClientsDumpCache.clear();

    bool serviceLock = tryLock(mServiceLock);
    auto cameraClients = mActiveClientManager.getAll();
    for (const auto &clientDescriptor : cameraClients) {
        if (clientDescriptor == nullptr) { continue; }
        sp<BasicClient> client = clientDescriptor->getValue();
        if (client.get() == nullptr) { continue; }
        client->stopWatchingTags(outFd);
    }
    dprintf(outFd, "Stopped watching all clients.\n");
    if (serviceLock) { mServiceLock.unlock(); }
    return OK;
}

status_t CameraService::printWatchedTags(const Vector<String16> &args, int outFd) {
    // Figure outFd refresh interval, if present in args
    useconds_t refreshTimeoutMs = 1000; // refresh every 1s by default
    if (args.size() > 2) {
        size_t intervalIdx; // index of '-n'
        for (intervalIdx = 2; intervalIdx < args.size() && String16("-n") != args[intervalIdx];
             intervalIdx++);

        size_t intervalValIdx = intervalIdx + 1;
        if (intervalValIdx < args.size()) {
            refreshTimeoutMs = strtol(String8(args[intervalValIdx].string()), nullptr, 10);
            if (errno) { return BAD_VALUE; }
        }
    }

    mLogLock.lock();
    bool serviceLock = tryLock(mServiceLock);
    // get all watched clients that are currently connected
    std::set<String16> connectedMoniterdClients;
    for (const auto &clientDescriptor: mActiveClientManager.getAll()) {
        if (clientDescriptor == nullptr) { continue; }

        sp<BasicClient> client = clientDescriptor->getValue();
        if (client.get() == nullptr) { continue; }
        if (!isClientWatchedLocked(client.get())) { continue; }

        connectedMoniterdClients.emplace(client->getPackageName());
    }
    if (serviceLock) { mServiceLock.unlock(); }

    // Print entries in mWatchedClientsDumpCache for clients that are not connected
    for (const auto &kv: mWatchedClientsDumpCache) {
        const String16 &package = kv.first;
        if (connectedMoniterdClients.find(package) != connectedMoniterdClients.end()) {
            continue;
        }

        dprintf(outFd, "Client: %s\n", String8(package).string());
        dprintf(outFd, "%s\n", kv.second.c_str());
    }
    mLogLock.unlock();

    if (connectedMoniterdClients.empty()) {
        dprintf(outFd, "No watched client active.\n");
        return OK;
    }

    // For connected watched clients, print monitored tags live
    return printWatchedTagsUntilInterrupt(refreshTimeoutMs  * 1000, outFd);
}

status_t CameraService::printWatchedTagsUntilInterrupt(useconds_t refreshMicros, int outFd) {
    std::unordered_map<std::string, std::string> cameraToLastEvent;
    auto cameraClients = mActiveClientManager.getAll();

    if (cameraClients.empty()) {
        dprintf(outFd, "No clients connected.\n");
        return OK;
    }

    dprintf(outFd, "Press Ctrl + C to exit...\n\n");
    while (true) {
        for (const auto& clientDescriptor : cameraClients) {
            Mutex::Autolock lock(mLogLock);
            if (clientDescriptor == nullptr) { continue; }
            const char* cameraId = clientDescriptor->getKey().string();

            // This also initializes the map entries with an empty string
            const std::string& lastPrintedEvent = cameraToLastEvent[cameraId];

            sp<BasicClient> client = clientDescriptor->getValue();
            if (client.get() == nullptr) { continue; }
            if (!isClientWatchedLocked(client.get())) { continue; }

            std::vector<std::string> latestEvents;
            client->dumpWatchedEventsToVector(latestEvents);

            if (!latestEvents.empty()) {
                printNewWatchedEvents(outFd,
                                      cameraId,
                                      client->getPackageName(),
                                      latestEvents,
                                      lastPrintedEvent);
                cameraToLastEvent[cameraId] = latestEvents[0];
            }
        }
        usleep(refreshMicros);  // convert ms to us
    }
    return OK;
}

void CameraService::printNewWatchedEvents(int outFd,
                                          const char *cameraId,
                                          const String16 &packageName,
                                          const std::vector<std::string> &events,
                                          const std::string &lastPrintedEvent) {
    if (events.empty()) { return; }

    // index of lastPrintedEvent in events.
    // lastPrintedIdx = events.size() if lastPrintedEvent is not in events
    size_t lastPrintedIdx;
    for (lastPrintedIdx = 0;
         lastPrintedIdx < events.size() && lastPrintedEvent != events[lastPrintedIdx];
         lastPrintedIdx++);

    if (lastPrintedIdx == 0) { return; } // early exit if no new event in `events`

    const char *printPackageName = String8(packageName).string();
    // print events in chronological order (latest event last)
    size_t idxToPrint = lastPrintedIdx;
    do {
        idxToPrint--;
        dprintf(outFd, "%s:%s  %s", cameraId, printPackageName, events[idxToPrint].c_str());
    } while (idxToPrint != 0);
}

void CameraService::parseClientsToWatchLocked(String8 clients) {
    mWatchedClientPackages.clear();

    const char *allSentinel = String8(kWatchAllClientsFlag).string();

    char *tokenized = clients.lockBuffer(clients.size());
    char *savePtr;
    char *nextClient = strtok_r(tokenized, ",", &savePtr);

    while (nextClient != nullptr) {
        if (strcmp(nextClient, allSentinel) == 0) {
            // Don't need to track any other package if 'all' is present
            mWatchedClientPackages.clear();
            mWatchedClientPackages.emplace(kWatchAllClientsFlag);
            break;
        }

        // track package names
        mWatchedClientPackages.emplace(nextClient);
        nextClient = strtok_r(nullptr, ",", &savePtr);
    }
    clients.unlockBuffer();
}

status_t CameraService::printHelp(int out) {
    return dprintf(out, "Camera service commands:\n"
        "  get-uid-state <PACKAGE> [--user USER_ID] gets the uid state\n"
@@ -4692,9 +4968,20 @@ status_t CameraService::printHelp(int out) {
        "      Valid values 0=OFF, 1=ON for JPEG\n"
        "  get-image-dump-mask returns the current image-dump-mask value\n"
        "  set-camera-mute <0/1> enable or disable camera muting\n"
        "  watch <start|stop|dump|live> manages tag monitoring in connected clients\n"
        "  help print this message\n");
}

bool CameraService::isClientWatched(const BasicClient *client) {
    Mutex::Autolock lock(mLogLock);
    return isClientWatchedLocked(client);
}

bool CameraService::isClientWatchedLocked(const BasicClient *client) {
    return mWatchedClientPackages.find(kWatchAllClientsFlag) != mWatchedClientPackages.end() ||
           mWatchedClientPackages.find(client->getPackageName()) != mWatchedClientPackages.end();
}

int32_t CameraService::updateAudioRestriction() {
    Mutex::Autolock lock(mServiceLock);
    return updateAudioRestrictionLocked();
+56 −0
Original line number Diff line number Diff line
@@ -272,6 +272,10 @@ public:
        // Internal dump method to be called by CameraService
        virtual status_t dumpClient(int fd, const Vector<String16>& args) = 0;

        virtual status_t startWatchingTags(const String8 &tags, int outFd);
        virtual status_t stopWatchingTags(int outFd);
        virtual status_t dumpWatchedEventsToVector(std::vector<std::string> &out);

        // Return the package name for this client
        virtual String16 getPackageName() const;

@@ -825,6 +829,14 @@ private:
    RingBuffer<String8> mEventLog;
    Mutex mLogLock;

    // set of client package names to watch. if this set contains 'all', then all clients will
    // be watched. Access should be guarded by mLogLock
    std::set<String16> mWatchedClientPackages;
    // cache of last monitored tags dump immediately before the client disconnects. If a client
    // re-connects, its entry is not updated until it disconnects again. Access should be guarded
    // by mLogLock
    std::map<String16, std::string> mWatchedClientsDumpCache;

    // The last monitored tags set by client
    String8 mMonitorTags;

@@ -957,6 +969,8 @@ private:
     */
    void dumpEventLog(int fd);

    void cacheClientTagDumpIfNeeded(const char *cameraId, BasicClient *client);

    /**
     * This method will acquire mServiceLock
     */
@@ -1149,9 +1163,47 @@ private:
    // Set the camera mute state
    status_t handleSetCameraMute(const Vector<String16>& args);

    // Handle 'watch' command as passed through 'cmd'
    status_t handleWatchCommand(const Vector<String16> &args, int outFd);

    // Enable tag monitoring of the given tags in provided clients
    status_t startWatchingTags(const Vector<String16> &args, int outFd);

    // Disable tag monitoring
    status_t stopWatchingTags(int outFd);

    // Print events of monitored tags in all cached and attached clients
    status_t printWatchedTags(const Vector<String16> &args, int outFd);

    // Print events of monitored tags in all attached clients as they are captured. New events are
    // fetched every `refreshMicros` us
    // NOTE: This function does not terminate unless interrupted.
    status_t printWatchedTagsUntilInterrupt(useconds_t refreshMicros, int outFd);

    // Print all events in vector `events' that came after lastPrintedEvent
    static void printNewWatchedEvents(int outFd,
                                      const char *cameraId,
                                      const String16 &packageName,
                                      const std::vector<std::string> &events,
                                      const std::string &lastPrintedEvent);

    // Parses comma separated clients list and adds them to mWatchedClientPackages.
    // Does not acquire mLogLock before modifying mWatchedClientPackages. It is the caller's
    // responsibility to acquire mLogLock before calling this function.
    void parseClientsToWatchLocked(String8 clients);

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

    // Returns true if client should monitor tags based on the contents of mWatchedClientPackages.
    // Acquires mLogLock before querying mWatchedClientPackages.
    bool isClientWatched(const BasicClient *client);

    // Returns true if client should monitor tags based on the contents of mWatchedClientPackages.
    // Does not acquire mLogLock before querying mWatchedClientPackages. It is the caller's
    // responsibility to acquire mLogLock before calling this functions.
    bool isClientWatchedLocked(const BasicClient *client);

    /**
     * Get the current system time as a formatted string.
     */
@@ -1182,6 +1234,10 @@ private:
    // Use separate keys for offline devices.
    static const String8 kOfflineDevice;

    // Sentinel value to be stored in `mWatchedClientsPackages` to indicate that all clients should
    // be watched.
    static const String16 kWatchAllClientsFlag;

    // TODO: right now each BasicClient holds one AppOpsManager instance.
    // We can refactor the code so all of clients share this instance
    AppOpsManager mAppOps;
+29 −0
Original line number Diff line number Diff line
@@ -1797,6 +1797,35 @@ status_t CameraDeviceClient::dumpClient(int fd, const Vector<String16>& args) {
    return dumpDevice(fd, args);
}

status_t CameraDeviceClient::startWatchingTags(const String8 &tags, int out) {
    sp<CameraDeviceBase> device = mDevice;
    if (!device) {
        dprintf(out, "  Device is detached.");
        return OK;
    }
    device->startWatchingTags(tags);
    return OK;
}

status_t CameraDeviceClient::stopWatchingTags(int out) {
    sp<CameraDeviceBase> device = mDevice;
    if (!device) {
        dprintf(out, "  Device is detached.");
        return OK;
    }
    device->stopWatchingTags();
    return OK;
}

status_t CameraDeviceClient::dumpWatchedEventsToVector(std::vector<std::string> &out) {
    sp<CameraDeviceBase> device = mDevice;
    if (!device) {
        return OK;
    }
    device->dumpWatchedEventsToVector(out);
    return OK;
}

void CameraDeviceClient::notifyError(int32_t errorCode,
                                     const CaptureResultExtras& resultExtras) {
    // Thread safe. Don't bother locking.
+4 −0
Original line number Diff line number Diff line
@@ -199,6 +199,10 @@ public:

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

    virtual status_t      startWatchingTags(const String8 &tags, int out);
    virtual status_t      stopWatchingTags(int out);
    virtual status_t      dumpWatchedEventsToVector(std::vector<std::string> &out);

    /**
     * Device listener interface
     */
+12 −0
Original line number Diff line number Diff line
@@ -110,6 +110,18 @@ status_t CameraOfflineSessionClient::dumpClient(int fd, const Vector<String16>&
    return OK;
}

status_t CameraOfflineSessionClient::startWatchingTags(const String8 &tags, int outFd) {
    return BasicClient::startWatchingTags(tags, outFd);
}

status_t CameraOfflineSessionClient::stopWatchingTags(int outFd) {
    return BasicClient::stopWatchingTags(outFd);
}

status_t CameraOfflineSessionClient::dumpWatchedEventsToVector(std::vector<std::string> &out) {
    return BasicClient::dumpWatchedEventsToVector(out);
}

binder::Status CameraOfflineSessionClient::disconnect() {
    Mutex::Autolock icl(mBinderSerializationLock);

Loading