Statsd -> Perfetto integration
This CL invokes the perfetto client utility to start the collection of a trace when an anomaly that subscribed to Perfetto is detected. The code simply spawns the /system/bin/perfetto client and passes the trace config via stdin. The client takes care of the dropbox upload. The CollectPerfettoTraceAndUploadToDropbox() function does NOT wait for the full trace collection (in order to avoid blocking statsd) and instead returns immediately after having spawned perfetto. Change-Id: I4f02067bad7a46ede7b6e4841cdcf381c1a4e2a7 Bug: 71795552
This commit is contained in:
@@ -781,6 +781,7 @@ LOCAL_PROTOC_FLAGS := \
|
||||
LOCAL_SOURCE_FILES_ALL_GENERATED := true
|
||||
LOCAL_SRC_FILES := \
|
||||
cmds/am/proto/instrumentation_data.proto \
|
||||
cmds/statsd/src/perfetto/perfetto_config.proto \
|
||||
$(call all-proto-files-under, core/proto) \
|
||||
$(call all-proto-files-under, libs/incident/proto) \
|
||||
$(call all-proto-files-under, cmds/statsd/src)
|
||||
|
||||
@@ -34,6 +34,7 @@ statsd_common_src := \
|
||||
src/config/ConfigKey.cpp \
|
||||
src/config/ConfigListener.cpp \
|
||||
src/config/ConfigManager.cpp \
|
||||
src/external/Perfetto.cpp \
|
||||
src/external/StatsPuller.cpp \
|
||||
src/external/StatsCompanionServicePuller.cpp \
|
||||
src/external/SubsystemSleepStatePuller.cpp \
|
||||
@@ -57,6 +58,7 @@ statsd_common_src := \
|
||||
src/metrics/MetricsManager.cpp \
|
||||
src/metrics/metrics_manager_util.cpp \
|
||||
src/packages/UidMap.cpp \
|
||||
src/perfetto/perfetto_config.proto \
|
||||
src/storage/StorageManager.cpp \
|
||||
src/StatsLogProcessor.cpp \
|
||||
src/StatsService.cpp \
|
||||
@@ -209,6 +211,7 @@ LOCAL_MODULE := statsdprotolite
|
||||
LOCAL_SRC_FILES := \
|
||||
src/stats_log.proto \
|
||||
src/statsd_config.proto \
|
||||
src/perfetto/perfetto_config.proto \
|
||||
src/atoms.proto
|
||||
|
||||
LOCAL_PROTOC_OPTIMIZE_TYPE := lite
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "Log.h"
|
||||
|
||||
#include "AnomalyTracker.h"
|
||||
#include "external/Perfetto.h"
|
||||
#include "guardrail/StatsdStats.h"
|
||||
|
||||
#include <android/os/IIncidentManager.h>
|
||||
@@ -239,7 +240,7 @@ void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) {
|
||||
}
|
||||
break;
|
||||
case Subscription::SubscriberInformationCase::kPerfettoDetails:
|
||||
ALOGW("Perfetto reports not implemented.");
|
||||
CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
111
cmds/statsd/src/external/Perfetto.cpp
vendored
Normal file
111
cmds/statsd/src/external/Perfetto.cpp
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
const char kDropboxTag[] = "perfetto";
|
||||
}
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config) {
|
||||
ALOGD("Starting trace collection through perfetto");
|
||||
|
||||
if (!config.has_trace_config()) {
|
||||
ALOGE("The perfetto trace config is empty, aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
android::base::unique_fd readPipe;
|
||||
android::base::unique_fd writePipe;
|
||||
if (!android::base::Pipe(&readPipe, &writePipe)) {
|
||||
ALOGE("pipe() failed while calling the Perfetto client: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
ALOGE("fork() failed while calling the Perfetto client: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
// Child process.
|
||||
|
||||
// No malloc calls or library calls after this point. Remember that even
|
||||
// ALOGx (aka android_printLog()) can use dynamic memory for vsprintf().
|
||||
|
||||
writePipe.reset(); // Close the write end (owned by the main process).
|
||||
|
||||
// Replace stdin with |readPipe| so the main process can write into it.
|
||||
if (dup2(readPipe.get(), STDIN_FILENO) < 0) _exit(1);
|
||||
execl("/system/bin/perfetto", "perfetto", "--background", "--config", "-", "--dropbox",
|
||||
kDropboxTag, nullptr);
|
||||
|
||||
// execl() doesn't return in case of success, if we get here something failed.
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Main process.
|
||||
|
||||
readPipe.reset(); // Close the read end (owned by the child process).
|
||||
|
||||
// Using fopen() because fwrite() has the right logic to chunking write()
|
||||
// over a pipe (see __sfvwrite()).
|
||||
FILE* writePipeStream = fdopen(writePipe.get(), "wb");
|
||||
if (!writePipeStream) {
|
||||
ALOGE("fdopen() failed while calling the Perfetto client: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string cfgProto = config.trace_config().SerializeAsString();
|
||||
size_t bytesWritten = fwrite(cfgProto.data(), 1, cfgProto.size(), writePipeStream);
|
||||
fclose(writePipeStream);
|
||||
if (bytesWritten != cfgProto.size() || cfgProto.size() == 0) {
|
||||
ALOGE("fwrite() failed (ret: %zd) while calling the Perfetto client: %s", bytesWritten,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// This does NOT wait for the full duration of the trace. It just waits until the process
|
||||
// has read the config from stdin and detached.
|
||||
int childStatus = 0;
|
||||
waitpid(pid, &childStatus, 0);
|
||||
if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) != 0) {
|
||||
ALOGE("Child process failed (0x%x) while calling the Perfetto client", childStatus);
|
||||
return false;
|
||||
}
|
||||
|
||||
ALOGD("CollectPerfettoTraceAndUploadToDropbox() succeeded");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
35
cmds/statsd/src/external/Perfetto.h
vendored
Normal file
35
cmds/statsd/src/external/Perfetto.h
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
using android::os::StatsLogEventWrapper;
|
||||
|
||||
namespace android {
|
||||
namespace os {
|
||||
namespace statsd {
|
||||
|
||||
class PerfettoDetails; // Declared in statsd_config.pb.h
|
||||
|
||||
// Starts the collection of a Perfetto trace with the given |config|.
|
||||
// The trace is uploaded to Dropbox by the perfetto cmdline util once done.
|
||||
// This method returns immediately after passing the config and does NOT wait
|
||||
// for the full duration of the trace.
|
||||
bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config);
|
||||
|
||||
} // namespace statsd
|
||||
} // namespace os
|
||||
} // namespace android
|
||||
61
cmds/statsd/src/perfetto/perfetto_config.proto
Normal file
61
cmds/statsd/src/perfetto/perfetto_config.proto
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
package perfetto.protos;
|
||||
|
||||
message DataSourceConfig {
|
||||
message FtraceConfig {
|
||||
repeated string event_names = 1;
|
||||
}
|
||||
|
||||
optional string name = 1;
|
||||
|
||||
optional uint32 target_buffer = 2;
|
||||
|
||||
optional FtraceConfig ftrace_config = 100;
|
||||
}
|
||||
|
||||
message TraceConfig {
|
||||
message BufferConfig {
|
||||
optional uint32 size_kb = 1;
|
||||
|
||||
enum OptimizeFor {
|
||||
DEFAULT = 0;
|
||||
ONE_SHOT_READ = 1;
|
||||
|
||||
}
|
||||
optional OptimizeFor optimize_for = 3;
|
||||
|
||||
enum FillPolicy {
|
||||
UNSPECIFIED = 0;
|
||||
RING_BUFFER = 1;
|
||||
}
|
||||
optional FillPolicy fill_policy = 4;
|
||||
}
|
||||
repeated BufferConfig buffers = 1;
|
||||
|
||||
message DataSource {
|
||||
optional protos.DataSourceConfig config = 1;
|
||||
|
||||
repeated string producer_name_filter = 2;
|
||||
}
|
||||
repeated DataSource data_sources = 2;
|
||||
|
||||
optional uint32 duration_ms = 3;
|
||||
}
|
||||
@@ -22,6 +22,8 @@ package android.os.statsd;
|
||||
option java_package = "com.android.internal.os";
|
||||
option java_outer_classname = "StatsdConfigProto";
|
||||
|
||||
import "frameworks/base/cmds/statsd/src/perfetto/perfetto_config.proto";
|
||||
|
||||
enum Position {
|
||||
POSITION_UNKNOWN = 0;
|
||||
FIRST = 1;
|
||||
@@ -272,7 +274,7 @@ message IncidentdDetails {
|
||||
}
|
||||
|
||||
message PerfettoDetails {
|
||||
optional int32 perfetto_stuff = 1;
|
||||
optional perfetto.protos.TraceConfig trace_config = 1;
|
||||
}
|
||||
|
||||
message Subscription {
|
||||
|
||||
@@ -21,9 +21,11 @@ LOCAL_PACKAGE_NAME := StatsdDogfood
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
LOCAL_SRC_FILES += ../../src/stats_log.proto \
|
||||
../../src/atoms.proto \
|
||||
../../src/perfetto/perfetto_config.proto \
|
||||
../../src/statsd_config.proto
|
||||
|
||||
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
|
||||
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := platformprotoslite
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ LOCAL_PACKAGE_NAME := StatsdLoadtest
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
LOCAL_SRC_FILES += ../../src/stats_log.proto \
|
||||
../../src/atoms.proto \
|
||||
../../src/perfetto/perfetto_config.proto \
|
||||
../../src/statsd_config.proto
|
||||
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../../src/
|
||||
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
|
||||
|
||||
Reference in New Issue
Block a user