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

Commit 7e53cadf authored by Avichal Rakesh's avatar Avichal Rakesh
Browse files

Add 'watch' command to CameraService

Currently there is no way to monitor tags and dump per frame data from
Camera devices without calling dumpsys, which in turn dumps a lot of
unnecessary information.

This CL adds a 'watch' command to CameraService which can be called
through `cmd`. 'watch' provides a path to manage tag monitoring without
dumpsys. 'watch' currently has four functions:
1. start <taglist>: starts mornitoring the provided tags in attached
                    devices.
2. stop: stop monitoring all tags
3. live: prints monitored information to the terminal live
4. dump: dumps any collected camera traces

This CL adds a function to camera device each for the three tag
monitoring function listed above.

Test: n/a
Bug: 199746421
Change-Id: Ia5ce13f6e50c82085afcc676309cdbffef915a41
parent 65d1ee72
Loading
Loading
Loading
Loading
+148 −2
Original line number Diff line number Diff line
@@ -3115,6 +3115,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 +4151,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();
@@ -4534,9 +4549,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 +4697,134 @@ status_t CameraService::handleSetCameraMute(const Vector<String16>& args) {
    return OK;
}

status_t CameraService::handleWatchCommand(const Vector<String16>& args, int out) {
    if (args.size() == 3 && args[1] == String16("start")) {
        return startWatchingTags(args[2], out);
    } else if (args.size() == 2 && args[1] == String16("dump")) {
        return camera3::CameraTraces::dump(out);
    } else if (args.size() == 2 && args[1] == String16("stop")) {
        return stopWatchingTags(out);
    } else if (args.size() >= 2 && args[1] == String16("live")) {
        return printWatchedTagsUntilInterrupt(args, out);
    }
    dprintf(out, "Camera service watch commands:\n"
                 "  start <comma_separated_tag_list> starts watching the provided tags\n"
                 "                                   recognizes shorthands like '3a'\n"
                 "  dump dumps camera trace\n"
                 "  stop stops watching all tags\n"
                 "  live prints the monitored information in real time\n"
                 "        Hit Ctrl+C to stop.\n");
  return BAD_VALUE;
}

status_t CameraService::startWatchingTags(const String16 &tags, int outFd) {
    // track tags to initialize future clients with the monitoring information
    mMonitorTags = String8(tags);

    auto cameraClients = mActiveClientManager.getAll();
    for (const auto &clientDescriptor: cameraClients) {
        if (clientDescriptor == nullptr) { continue; }
        sp<BasicClient> client = clientDescriptor->getValue();
        if (client.get() == nullptr) { continue; }
        client->startWatchingTags(mMonitorTags, outFd);
    }
    return OK;
}

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

    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);
    }
    return OK;
}

status_t CameraService::printWatchedTagsUntilInterrupt(const Vector<String16> &args, int outFd) {
    useconds_t refreshTimeoutMs = 1000; // refresh every 1s by default

    if (args.size() > 2) {
        size_t intervalIdx; // index of refresh interval argument
        for (intervalIdx = 2;
             intervalIdx < args.size()
                && String16("-n") != args[intervalIdx]
                && String16("--interval") != 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; }
        }
    }

    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) {
            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; }

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

            if (!latestEvents.empty()) {
                printNewWatchedEvents(outFd,
                                      cameraId,
                                      client->getPackageName(),
                                      latestEvents,
                                      lastPrintedEvent);
                cameraToLastEvent[cameraId] = latestEvents[0];
            }
        }
        usleep(refreshTimeoutMs * 1000);  // 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);
}

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,6 +4837,7 @@ 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");
}

+24 −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;

@@ -1149,6 +1153,26 @@ 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 out);

    // Enable tag monitoring of the given tags in all attached clients
    status_t startWatchingTags(const String16 &tags, int outFd);

    // Disable tag monitoring in all attached clients
    status_t stopWatchingTags(int outFd);

    // Print events of monitored tags in all attached devices as they are captured
    // NOTE: This function does not terminate unless interrupted.
    status_t printWatchedTagsUntilInterrupt(const Vector<String16> &args, 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);

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

+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