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

Commit 6ede28bc authored by Tej Singh's avatar Tej Singh
Browse files

Statsd sends active config broadcasts

Statsd now sends active configs changed broadcasts when needed per uid.
Also made an adb command to help debug.

More gts tests and unit tests required, will follow.
Test: GTS in topic
Bug: 123372077
Change-Id: Ib079018ded85d002581ffc2ba1240138ce7a54e7
parent 5c5fbf11
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -367,7 +367,8 @@ sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const Stat
    sp<AlarmMonitor> periodicAlarmMonitor;
    sp<StatsLogProcessor> processor =
            new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
                                  timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; });
                                  timeBaseSec * NS_PER_SEC, [](const ConfigKey&) { return true; },
                                  [](const int&, const vector<int64_t>&) { return true; });
    processor->OnConfigUpdated(timeBaseSec * NS_PER_SEC, key, config);
    return processor;
}
+78 −1
Original line number Diff line number Diff line
@@ -88,12 +88,15 @@ StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
                                     const sp<AlarmMonitor>& anomalyAlarmMonitor,
                                     const sp<AlarmMonitor>& periodicAlarmMonitor,
                                     const int64_t timeBaseNs,
                                     const std::function<bool(const ConfigKey&)>& sendBroadcast)
                                     const std::function<bool(const ConfigKey&)>& sendBroadcast,
                                     const std::function<bool(
                                            const int&, const vector<int64_t>&)>& activateBroadcast)
    : mUidMap(uidMap),
      mPullerManager(pullerManager),
      mAnomalyAlarmMonitor(anomalyAlarmMonitor),
      mPeriodicAlarmMonitor(periodicAlarmMonitor),
      mSendBroadcast(sendBroadcast),
      mSendActivationBroadcast(activateBroadcast),
      mTimeBaseNs(timeBaseNs),
      mLargestTimestampSeen(0),
      mLastTimestampSeen(0) {
@@ -223,11 +226,73 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) {
        mapIsolatedUidToHostUidIfNecessaryLocked(event);
    }

    std::unordered_set<int> uidsWithActiveConfigsChanged;
    std::unordered_map<int, std::vector<int64_t>> activeConfigsPerUid;
    // pass the event to metrics managers.
    for (auto& pair : mMetricsManagers) {
        int uid = pair.first.GetUid();
        int64_t configId = pair.first.GetId();
        bool isPrevActive = pair.second->isActive();
        pair.second->onLogEvent(*event);
        bool isCurActive = pair.second->isActive();
        // Map all active configs by uid.
        if (isCurActive) {
            auto activeConfigs = activeConfigsPerUid.find(uid);
            if (activeConfigs != activeConfigsPerUid.end()) {
                activeConfigs->second.push_back(configId);
            } else {
                vector<int64_t> newActiveConfigs;
                newActiveConfigs.push_back(configId);
                activeConfigsPerUid[uid] = newActiveConfigs;
            }
        }
        // The activation state of this config changed.
        if (isPrevActive != isCurActive) {
            VLOG("Active status changed for uid  %d", uid);
            uidsWithActiveConfigsChanged.insert(uid);
            StatsdStats::getInstance().noteActiveStatusChanged(pair.first, isCurActive);
        }
        flushIfNecessaryLocked(event->GetElapsedTimestampNs(), pair.first, *(pair.second));
    }

    for (int uid : uidsWithActiveConfigsChanged) {
        // Send broadcast so that receivers can pull data.
        auto lastBroadcastTime = mLastActivationBroadcastTimes.find(uid);
        if (lastBroadcastTime != mLastActivationBroadcastTimes.end()) {
            if (currentTimestampNs - lastBroadcastTime->second <
                    StatsdStats::kMinActivationBroadcastPeriodNs) {
                VLOG("StatsD would've sent an activation broadcast but the rate limit stopped us.");
                return;
            }
        }
        auto activeConfigs = activeConfigsPerUid.find(uid);
        if (activeConfigs != activeConfigsPerUid.end()) {
            if (mSendActivationBroadcast(uid, activeConfigs->second)) {
                VLOG("StatsD sent activation notice for uid %d", uid);
                mLastActivationBroadcastTimes[uid] = currentTimestampNs;
            }
        } else {
            std::vector<int64_t> emptyActiveConfigs;
            if (mSendActivationBroadcast(uid, emptyActiveConfigs)) {
                VLOG("StatsD sent EMPTY activation notice for uid %d", uid);
                mLastActivationBroadcastTimes[uid] = currentTimestampNs;
            }
        }
    }
}

void StatsLogProcessor::GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs) {
    std::lock_guard<std::mutex> lock(mMetricsMutex);
    GetActiveConfigsLocked(uid, outActiveConfigs);
}

void StatsLogProcessor::GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs) {
    outActiveConfigs.clear();
    for (auto& pair : mMetricsManagers) {
        if (pair.first.GetUid() == uid && pair.second->isActive()) {
            outActiveConfigs.push_back(pair.first.GetId());
        }
    }
}

void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
@@ -444,6 +509,18 @@ void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {

    mLastBroadcastTimes.erase(key);

    int uid = key.GetUid();
    bool lastConfigForUid = true;
    for (auto it : mMetricsManagers) {
        if (it.first.GetUid() == uid) {
            lastConfigForUid = false;
            break;
        }
    }
    if (lastConfigForUid) {
        mLastActivationBroadcastTimes.erase(uid);
    }

    if (mMetricsManagers.empty()) {
        mPullerManager->ForceClearPullerCache();
    }
+14 −1
Original line number Diff line number Diff line
@@ -49,7 +49,9 @@ public:
                      const sp<AlarmMonitor>& anomalyAlarmMonitor,
                      const sp<AlarmMonitor>& subscriberTriggerAlarmMonitor,
                      const int64_t timeBaseNs,
                      const std::function<bool(const ConfigKey&)>& sendBroadcast);
                      const std::function<bool(const ConfigKey&)>& sendBroadcast,
                      const std::function<bool(const int&,
                                               const vector<int64_t>&)>& sendActivationBroadcast);
    virtual ~StatsLogProcessor();

    void OnLogEvent(LogEvent* event);
@@ -60,6 +62,8 @@ public:

    size_t GetMetricsSize(const ConfigKey& key) const;

    void GetActiveConfigs(const int uid, vector<int64_t>& outActiveConfigs);

    void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
                      const bool include_current_partial_bucket, const bool erase_data,
                      const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
@@ -125,6 +129,9 @@ private:

    std::unordered_map<ConfigKey, long> mLastBroadcastTimes;

    // Last time we sent a broadcast to this uid that the active configs had changed.
    std::unordered_map<int, long> mLastActivationBroadcastTimes;

    // Tracks when we last checked the bytes consumed for each config key.
    std::unordered_map<ConfigKey, long> mLastByteSizeTimes;

@@ -144,6 +151,8 @@ private:
    void OnConfigUpdatedLocked(
        const int64_t currentTimestampNs, const ConfigKey& key, const StatsdConfig& config);

    void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);

    void WriteDataToDiskLocked(const DumpReportReason dumpReportReason);
    void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
                               const DumpReportReason dumpReportReason);
@@ -174,6 +183,10 @@ private:
    // to retrieve the stored data.
    std::function<bool(const ConfigKey& key)> mSendBroadcast;

    // Function used to send a broadcast so that receiver can be notified of which configs
    // are currently active.
    std::function<bool(const int& uid, const vector<int64_t>& configIds)> mSendActivationBroadcast;

    const int64_t mTimeBaseNs;

    // Largest timestamp of the events that we have processed.
+95 −3
Original line number Diff line number Diff line
@@ -176,6 +176,21 @@ StatsService::StatsService(const sp<Looper>& handlerLooper)
                    sc->sendDataBroadcast(receiver, mProcessor->getLastReportTimeNs(key));
                    return true;
                }
            },
            [this](const int& uid, const vector<int64_t>& activeConfigs) {
                auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
                sp<IStatsCompanionService> sc = getStatsCompanionService();
                if (sc == nullptr) {
                    VLOG("Could not access statsCompanion");
                    return false;
                } else if (receiver == nullptr) {
                    VLOG("Could not find receiver for uid %d", uid);
                    return false;
                } else {
                    sc->sendActiveConfigsChangedBroadcast(receiver, activeConfigs);
                    VLOG("StatsService::active configs broadcast succeeded for uid %d" , uid);
                    return true;
                }
            });

    mConfigManager->AddListener(mProcessor);
@@ -357,6 +372,9 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
        if (!args[0].compare(String8("print-logs"))) {
            return cmd_print_logs(out, args);
        }
        if (!args[0].compare(String8("send-active-configs"))) {
            return cmd_trigger_active_config_broadcast(out, args);
        }
        if (!args[0].compare(String8("data-subscribe"))) {
            if (mShellSubscriber == nullptr) {
                mShellSubscriber = new ShellSubscriber(mUidMap, mPullerManager);
@@ -447,6 +465,19 @@ void StatsService::print_cmd_help(int out) {
    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
    dprintf(out, "                calling uid is used.\n");
    dprintf(out, "  NAME          The name of the configuration\n");
    dprintf(out, "\n");
    dprintf(out, "\n");
    dprintf(out,
            "usage: adb shell cmd stats send-active-configs [--uid=UID] [--configs] "
            "[NAME1] [NAME2] [NAME3..]\n");
    dprintf(out, "  Send a broadcast that informs the subscriber of the current active configs.\n");
    dprintf(out, "  --uid=UID     The uid of the configurations. It is only possible to pass\n");
    dprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
    dprintf(out, "                calling uid is used.\n");
    dprintf(out, "  --configs     Send the list of configs in the name list instead of\n");
    dprintf(out, "                the currently active configs\n");
    dprintf(out, "  NAME LIST     List of configuration names to be included in the broadcast.\n");

    dprintf(out, "\n");
    dprintf(out, "\n");
    dprintf(out, "usage: adb shell cmd stats print-stats\n");
@@ -499,6 +530,59 @@ status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
    return NO_ERROR;
}

status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<String8>& args) {
    const int argCount = args.size();
    int uid;
    vector<int64_t> configIds;
    if (argCount == 1) {
        // Automatically pick the uid and send a broadcast that has no active configs.
        uid = IPCThreadState::self()->getCallingUid();
        mProcessor->GetActiveConfigs(uid, configIds);
    } else {
        int curArg = 1;
        if(args[curArg].find("--uid=") == 0) {
            string uidArgStr(args[curArg].c_str());
            string uidStr = uidArgStr.substr(6);
            if (!getUidFromString(uidStr.c_str(), uid)) {
                dprintf(out, "Invalid UID. Note that the config can only be set for "
                             "other UIDs on eng or userdebug builds.\n");
                return UNKNOWN_ERROR;
            }
            curArg++;
        } else {
            uid = IPCThreadState::self()->getCallingUid();
        }
        if (curArg == argCount || args[curArg] != "--configs") {
            VLOG("Reached end of args, or specify configs not set. Sending actual active configs,");
            mProcessor->GetActiveConfigs(uid, configIds);
        } else {
            // Flag specified, use the given list of configs.
            curArg++;
            for (int i = curArg; i < argCount; i++) {
                char* endp;
                int64_t configID = strtoll(args[i].c_str(), &endp, 10);
                if (endp == args[i].c_str() || *endp != '\0') {
                    dprintf(out, "Error parsing config ID.\n");
                    return UNKNOWN_ERROR;
                }
                VLOG("Adding config id %ld", static_cast<long>(configID));
                configIds.push_back(configID);
            }
        }
    }
    auto receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
    sp<IStatsCompanionService> sc = getStatsCompanionService();
    if (sc == nullptr) {
        VLOG("Could not access statsCompanion");
    } else if (receiver == nullptr) {
        VLOG("Could not find receiver for uid %d", uid);
    } else {
        sc->sendActiveConfigsChangedBroadcast(receiver, configIds);
        VLOG("StatsService::trigger active configs changed broadcast succeeded for uid %d" , uid);
    }
    return NO_ERROR;
}

status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& args) {
    const int argCount = args.size();
    if (argCount >= 2) {
@@ -762,7 +846,10 @@ status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
}

bool StatsService::getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid) {
    const char* s = args[uidArgIndex].c_str();
    return getUidFromString(args[uidArgIndex].c_str(), uid);
}

bool StatsService::getUidFromString(const char* s, int32_t& uid) {
    if (*s == '\0') {
        return false;
    }
@@ -998,8 +1085,13 @@ Status StatsService::setActiveConfigsChangedOperation(const sp<android::IBinder>
    ENFORCE_DUMP_AND_USAGE_STATS(packageName);

    IPCThreadState* ipc = IPCThreadState::self();
    mConfigManager->SetActiveConfigsChangedReceiver(ipc->getCallingUid(), intentSender);
    //TODO: Return the list of configs that are already active
    int uid = ipc->getCallingUid();
    mConfigManager->SetActiveConfigsChangedReceiver(uid, intentSender);
    if (output != nullptr) {
        mProcessor->GetActiveConfigs(uid, *output);
    } else {
        ALOGW("StatsService::setActiveConfigsChanged output was nullptr");
    }
    return Status::ok();
}

+15 −0
Original line number Diff line number Diff line
@@ -275,6 +275,12 @@ private:
     */
    status_t cmd_trigger_broadcast(int outFd, Vector<String8>& args);


    /**
     * Trigger an active configs changed broadcast.
     */
    status_t cmd_trigger_active_config_broadcast(int outFd, Vector<String8>& args);

    /**
     * Handle the config sub-command.
     */
@@ -340,6 +346,15 @@ private:
     */
    bool getUidFromArgs(const Vector<String8>& args, size_t uidArgIndex, int32_t& uid);

    /**
     * Writes the value of uidSting into uid.
     * Returns whether the uid is reasonable (type uid_t) and whether
     * 1. it is equal to the calling uid, or
     * 2. the device is mEngBuild, or
     * 3. the caller is AID_ROOT and the uid is AID_SHELL (i.e. ROOT can impersonate SHELL).
     */
     bool getUidFromString(const char* uidString, int32_t& uid);

    /**
     * Adds a configuration after checking permissions and obtaining UID from binder call.
     */
Loading