Merge tag 'android-security-10.0.0_r53' into int/10/fp2

Android security 10.0.0 release 53

* tag 'android-security-10.0.0_r53':

Change-Id: I58124a2ee66b62dbd54f46fd6c75dad8beffbe54
diff --git a/Android.bp b/Android.bp
index b7f12d2..a11041a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -117,6 +117,7 @@
     "src/tracing/core/trace_stats.cc",
     "src/tracing/core/trace_writer_impl.cc",
     "src/tracing/core/tracing_service_impl.cc",
+    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
   ],
   shared_libs: [
@@ -235,6 +236,7 @@
     ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_protos_perfetto_trace_zero_gen",
     ":perfetto_src_ipc_wire_protocol_gen",
+    "src/android_internal/lazy_library_loader.cc",
     "src/base/event.cc",
     "src/base/file_utils.cc",
     "src/base/metatrace.cc",
@@ -324,6 +326,7 @@
     "src/tracing/core/trace_stats.cc",
     "src/tracing/core/trace_writer_impl.cc",
     "src/tracing/core/tracing_service_impl.cc",
+    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
   ],
   shared_libs: [
@@ -428,6 +431,7 @@
     ":perfetto_protos_perfetto_trace_zero_gen",
     ":perfetto_src_ipc_wire_protocol_gen",
     ":perfetto_src_perfetto_cmd_protos_gen",
+    "src/android_internal/lazy_library_loader.cc",
     "src/base/android_task_runner.cc",
     "src/base/event.cc",
     "src/base/file_utils.cc",
@@ -492,6 +496,7 @@
     "src/tracing/core/trace_stats.cc",
     "src/tracing/core/trace_writer_impl.cc",
     "src/tracing/core/tracing_service_impl.cc",
+    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
   ],
   shared_libs: [
@@ -601,6 +606,7 @@
     ":perfetto_protos_perfetto_trace_trusted_lite_gen",
     ":perfetto_protos_perfetto_trace_zero_gen",
     ":perfetto_src_ipc_wire_protocol_gen",
+    "src/android_internal/lazy_library_loader.cc",
     "src/base/android_task_runner.cc",
     "src/base/event.cc",
     "src/base/file_utils.cc",
@@ -702,6 +708,7 @@
     "src/tracing/core/trace_stats.cc",
     "src/tracing/core/trace_writer_impl.cc",
     "src/tracing/core/tracing_service_impl.cc",
+    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
     "test/end_to_end_integrationtest.cc",
     "test/fake_producer.cc",
@@ -774,10 +781,12 @@
   srcs: [
     "protos/perfetto/common/android_log_constants.proto",
     "protos/perfetto/common/commit_data_request.proto",
+    "protos/perfetto/common/data_source_descriptor.proto",
     "protos/perfetto/common/descriptor.proto",
     "protos/perfetto/common/observable_events.proto",
     "protos/perfetto/common/sys_stats_counters.proto",
     "protos/perfetto/common/trace_stats.proto",
+    "protos/perfetto/common/tracing_service_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -786,10 +795,12 @@
   out: [
     "external/perfetto/protos/perfetto/common/android_log_constants.pb.cc",
     "external/perfetto/protos/perfetto/common/commit_data_request.pb.cc",
+    "external/perfetto/protos/perfetto/common/data_source_descriptor.pb.cc",
     "external/perfetto/protos/perfetto/common/descriptor.pb.cc",
     "external/perfetto/protos/perfetto/common/observable_events.pb.cc",
     "external/perfetto/protos/perfetto/common/sys_stats_counters.pb.cc",
     "external/perfetto/protos/perfetto/common/trace_stats.pb.cc",
+    "external/perfetto/protos/perfetto/common/tracing_service_state.pb.cc",
   ],
 }
 
@@ -799,10 +810,12 @@
   srcs: [
     "protos/perfetto/common/android_log_constants.proto",
     "protos/perfetto/common/commit_data_request.proto",
+    "protos/perfetto/common/data_source_descriptor.proto",
     "protos/perfetto/common/descriptor.proto",
     "protos/perfetto/common/observable_events.proto",
     "protos/perfetto/common/sys_stats_counters.proto",
     "protos/perfetto/common/trace_stats.proto",
+    "protos/perfetto/common/tracing_service_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -811,10 +824,12 @@
   out: [
     "external/perfetto/protos/perfetto/common/android_log_constants.pb.h",
     "external/perfetto/protos/perfetto/common/commit_data_request.pb.h",
+    "external/perfetto/protos/perfetto/common/data_source_descriptor.pb.h",
     "external/perfetto/protos/perfetto/common/descriptor.pb.h",
     "external/perfetto/protos/perfetto/common/observable_events.pb.h",
     "external/perfetto/protos/perfetto/common/sys_stats_counters.pb.h",
     "external/perfetto/protos/perfetto/common/trace_stats.pb.h",
+    "external/perfetto/protos/perfetto/common/tracing_service_state.pb.h",
   ],
   export_include_dirs: [
     "protos",
@@ -827,10 +842,12 @@
   srcs: [
     "protos/perfetto/common/android_log_constants.proto",
     "protos/perfetto/common/commit_data_request.proto",
+    "protos/perfetto/common/data_source_descriptor.proto",
     "protos/perfetto/common/descriptor.proto",
     "protos/perfetto/common/observable_events.proto",
     "protos/perfetto/common/sys_stats_counters.proto",
     "protos/perfetto/common/trace_stats.proto",
+    "protos/perfetto/common/tracing_service_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -840,10 +857,12 @@
   out: [
     "external/perfetto/protos/perfetto/common/android_log_constants.pbzero.cc",
     "external/perfetto/protos/perfetto/common/commit_data_request.pbzero.cc",
+    "external/perfetto/protos/perfetto/common/data_source_descriptor.pbzero.cc",
     "external/perfetto/protos/perfetto/common/descriptor.pbzero.cc",
     "external/perfetto/protos/perfetto/common/observable_events.pbzero.cc",
     "external/perfetto/protos/perfetto/common/sys_stats_counters.pbzero.cc",
     "external/perfetto/protos/perfetto/common/trace_stats.pbzero.cc",
+    "external/perfetto/protos/perfetto/common/tracing_service_state.pbzero.cc",
   ],
 }
 
@@ -853,10 +872,12 @@
   srcs: [
     "protos/perfetto/common/android_log_constants.proto",
     "protos/perfetto/common/commit_data_request.proto",
+    "protos/perfetto/common/data_source_descriptor.proto",
     "protos/perfetto/common/descriptor.proto",
     "protos/perfetto/common/observable_events.proto",
     "protos/perfetto/common/sys_stats_counters.proto",
     "protos/perfetto/common/trace_stats.proto",
+    "protos/perfetto/common/tracing_service_state.proto",
   ],
   tools: [
     "aprotoc",
@@ -866,10 +887,12 @@
   out: [
     "external/perfetto/protos/perfetto/common/android_log_constants.pbzero.h",
     "external/perfetto/protos/perfetto/common/commit_data_request.pbzero.h",
+    "external/perfetto/protos/perfetto/common/data_source_descriptor.pbzero.h",
     "external/perfetto/protos/perfetto/common/descriptor.pbzero.h",
     "external/perfetto/protos/perfetto/common/observable_events.pbzero.h",
     "external/perfetto/protos/perfetto/common/sys_stats_counters.pbzero.h",
     "external/perfetto/protos/perfetto/common/trace_stats.pbzero.h",
+    "external/perfetto/protos/perfetto/common/tracing_service_state.pbzero.h",
   ],
   export_include_dirs: [
     "protos",
@@ -884,7 +907,6 @@
     "protos/perfetto/config/android/packages_list_config.proto",
     "protos/perfetto/config/chrome/chrome_config.proto",
     "protos/perfetto/config/data_source_config.proto",
-    "protos/perfetto/config/data_source_descriptor.proto",
     "protos/perfetto/config/ftrace/ftrace_config.proto",
     "protos/perfetto/config/inode_file/inode_file_config.proto",
     "protos/perfetto/config/power/android_power_config.proto",
@@ -903,7 +925,6 @@
     "external/perfetto/protos/perfetto/config/android/packages_list_config.pb.cc",
     "external/perfetto/protos/perfetto/config/chrome/chrome_config.pb.cc",
     "external/perfetto/protos/perfetto/config/data_source_config.pb.cc",
-    "external/perfetto/protos/perfetto/config/data_source_descriptor.pb.cc",
     "external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pb.cc",
     "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pb.cc",
     "external/perfetto/protos/perfetto/config/power/android_power_config.pb.cc",
@@ -923,7 +944,6 @@
     "protos/perfetto/config/android/packages_list_config.proto",
     "protos/perfetto/config/chrome/chrome_config.proto",
     "protos/perfetto/config/data_source_config.proto",
-    "protos/perfetto/config/data_source_descriptor.proto",
     "protos/perfetto/config/ftrace/ftrace_config.proto",
     "protos/perfetto/config/inode_file/inode_file_config.proto",
     "protos/perfetto/config/power/android_power_config.proto",
@@ -942,7 +962,6 @@
     "external/perfetto/protos/perfetto/config/android/packages_list_config.pb.h",
     "external/perfetto/protos/perfetto/config/chrome/chrome_config.pb.h",
     "external/perfetto/protos/perfetto/config/data_source_config.pb.h",
-    "external/perfetto/protos/perfetto/config/data_source_descriptor.pb.h",
     "external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pb.h",
     "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pb.h",
     "external/perfetto/protos/perfetto/config/power/android_power_config.pb.h",
@@ -965,7 +984,6 @@
     "protos/perfetto/config/android/packages_list_config.proto",
     "protos/perfetto/config/chrome/chrome_config.proto",
     "protos/perfetto/config/data_source_config.proto",
-    "protos/perfetto/config/data_source_descriptor.proto",
     "protos/perfetto/config/ftrace/ftrace_config.proto",
     "protos/perfetto/config/inode_file/inode_file_config.proto",
     "protos/perfetto/config/power/android_power_config.proto",
@@ -985,7 +1003,6 @@
     "external/perfetto/protos/perfetto/config/android/packages_list_config.pbzero.cc",
     "external/perfetto/protos/perfetto/config/chrome/chrome_config.pbzero.cc",
     "external/perfetto/protos/perfetto/config/data_source_config.pbzero.cc",
-    "external/perfetto/protos/perfetto/config/data_source_descriptor.pbzero.cc",
     "external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pbzero.cc",
     "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pbzero.cc",
     "external/perfetto/protos/perfetto/config/power/android_power_config.pbzero.cc",
@@ -1005,7 +1022,6 @@
     "protos/perfetto/config/android/packages_list_config.proto",
     "protos/perfetto/config/chrome/chrome_config.proto",
     "protos/perfetto/config/data_source_config.proto",
-    "protos/perfetto/config/data_source_descriptor.proto",
     "protos/perfetto/config/ftrace/ftrace_config.proto",
     "protos/perfetto/config/inode_file/inode_file_config.proto",
     "protos/perfetto/config/power/android_power_config.proto",
@@ -1025,7 +1041,6 @@
     "external/perfetto/protos/perfetto/config/android/packages_list_config.pbzero.h",
     "external/perfetto/protos/perfetto/config/chrome/chrome_config.pbzero.h",
     "external/perfetto/protos/perfetto/config/data_source_config.pbzero.h",
-    "external/perfetto/protos/perfetto/config/data_source_descriptor.pbzero.h",
     "external/perfetto/protos/perfetto/config/ftrace/ftrace_config.pbzero.h",
     "external/perfetto/protos/perfetto/config/inode_file/inode_file_config.pbzero.h",
     "external/perfetto/protos/perfetto/config/power/android_power_config.pbzero.h",
@@ -2742,6 +2757,7 @@
     "src/tracing/core/trace_stats.cc",
     "src/tracing/core/trace_writer_impl.cc",
     "src/tracing/core/tracing_service_impl.cc",
+    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
     "src/tracing/ipc/consumer/consumer_ipc_client_impl.cc",
     "src/tracing/ipc/default_socket.cc",
@@ -2919,6 +2935,7 @@
     ":perfetto_src_protozero_testing_messages_zero_gen",
     ":perfetto_src_traced_probes_ftrace_test_messages_lite_gen",
     ":perfetto_src_traced_probes_ftrace_test_messages_zero_gen",
+    "src/android_internal/lazy_library_loader.cc",
     "src/base/android_task_runner.cc",
     "src/base/circular_queue_unittest.cc",
     "src/base/event.cc",
@@ -3104,6 +3121,7 @@
     "src/tracing/core/trace_writer_impl_unittest.cc",
     "src/tracing/core/tracing_service_impl.cc",
     "src/tracing/core/tracing_service_impl_unittest.cc",
+    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
     "src/tracing/ipc/posix_shared_memory_unittest.cc",
     "src/tracing/test/aligned_buffer_test.cc",
@@ -3478,6 +3496,7 @@
     "src/tracing/core/trace_stats.cc",
     "src/tracing/core/trace_writer_impl.cc",
     "src/tracing/core/tracing_service_impl.cc",
+    "src/tracing/core/tracing_service_state.cc",
     "src/tracing/core/virtual_destructors.cc",
   ],
   shared_libs: [
diff --git a/gn/standalone/proto_library.gni b/gn/standalone/proto_library.gni
index 2f46e9d..caa58d9 100644
--- a/gn/standalone/proto_library.gni
+++ b/gn/standalone/proto_library.gni
@@ -187,7 +187,9 @@
                              "visibility",
                            ])
 
+    set_sources_assignment_filter([ "*\.descriptor" ])
     sources = get_target_outputs(":$action_name")
+    set_sources_assignment_filter([])
 
     configs -= [ "//gn/standalone:extra_warnings" ]
     if (defined(invoker.extra_configs)) {
diff --git a/include/perfetto/tracing/core/BUILD.gn b/include/perfetto/tracing/core/BUILD.gn
index 1812133..78bc8e3 100644
--- a/include/perfetto/tracing/core/BUILD.gn
+++ b/include/perfetto/tracing/core/BUILD.gn
@@ -35,5 +35,6 @@
     "trace_stats.h",
     "trace_writer.h",
     "tracing_service.h",
+    "tracing_service_state.h",
   ]
 }
diff --git a/include/perfetto/tracing/core/consumer.h b/include/perfetto/tracing/core/consumer.h
index cf92253..d8d3f13 100644
--- a/include/perfetto/tracing/core/consumer.h
+++ b/include/perfetto/tracing/core/consumer.h
@@ -28,6 +28,7 @@
 class TraceConfig;
 class TracePacket;
 class TraceStats;
+class TracingServiceState;
 
 class PERFETTO_EXPORT Consumer {
  public:
diff --git a/include/perfetto/tracing/core/data_source_descriptor.h b/include/perfetto/tracing/core/data_source_descriptor.h
index af161ff..79346cc 100644
--- a/include/perfetto/tracing/core/data_source_descriptor.h
+++ b/include/perfetto/tracing/core/data_source_descriptor.h
@@ -18,7 +18,7 @@
  * AUTOGENERATED - DO NOT EDIT
  *******************************************************************************
  * This file has been generated from the protobuf message
- * perfetto/config/data_source_descriptor.proto
+ * perfetto/common/data_source_descriptor.proto
  * by
  * ../../tools/proto_to_cpp/proto_to_cpp.cc.
  * If you need to make changes here, change the .proto file and then run
diff --git a/include/perfetto/tracing/core/tracing_service.h b/include/perfetto/tracing/core/tracing_service.h
index fd10957..5b12e11 100644
--- a/include/perfetto/tracing/core/tracing_service.h
+++ b/include/perfetto/tracing/core/tracing_service.h
@@ -39,6 +39,7 @@
 class DataSourceDescriptor;
 class Producer;
 class SharedMemoryArbiter;
+class TracingServiceState;
 class TraceConfig;
 class TraceWriter;
 
@@ -202,6 +203,12 @@
   //
   // TODO(eseckler): Extend this to support producers & data sources.
   virtual void ObserveEvents(uint32_t enabled_event_types) = 0;
+
+  // Used to obtain the list of connected data sources and other info about
+  // the tracing service.
+  using QueryServiceStateCallback =
+      std::function<void(bool success, const TracingServiceState&)>;
+  virtual void QueryServiceState(QueryServiceStateCallback) = 0;
 };  // class ConsumerEndpoint.
 
 // The public API of the tracing Service business logic.
diff --git a/include/perfetto/tracing/core/tracing_service_state.h b/include/perfetto/tracing/core/tracing_service_state.h
new file mode 100644
index 0000000..f8a1373
--- /dev/null
+++ b/include/perfetto/tracing/core/tracing_service_state.h
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ */
+
+/*******************************************************************************
+ * AUTOGENERATED - DO NOT EDIT
+ *******************************************************************************
+ * This file has been generated from the protobuf message
+ * perfetto/common/tracing_service_state.proto
+ * by
+ * ../../tools/proto_to_cpp/proto_to_cpp.cc.
+ * If you need to make changes here, change the .proto file and then run
+ * ./tools/gen_tracing_cpp_headers_from_protos
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
+#define INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
+
+#include <stdint.h>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "perfetto/base/export.h"
+
+#include "perfetto/tracing/core/data_source_descriptor.h"
+
+// Forward declarations for protobuf types.
+namespace perfetto {
+namespace protos {
+class TracingServiceState;
+class TracingServiceState_Producer;
+class TracingServiceState_DataSource;
+class DataSourceDescriptor;
+}  // namespace protos
+}  // namespace perfetto
+
+namespace perfetto {
+
+class PERFETTO_EXPORT TracingServiceState {
+ public:
+  class PERFETTO_EXPORT Producer {
+   public:
+    Producer();
+    ~Producer();
+    Producer(Producer&&) noexcept;
+    Producer& operator=(Producer&&);
+    Producer(const Producer&);
+    Producer& operator=(const Producer&);
+    bool operator==(const Producer&) const;
+    bool operator!=(const Producer& other) const { return !(*this == other); }
+
+    // Conversion methods from/to the corresponding protobuf types.
+    void FromProto(const perfetto::protos::TracingServiceState_Producer&);
+    void ToProto(perfetto::protos::TracingServiceState_Producer*) const;
+
+    int32_t id() const { return id_; }
+    void set_id(int32_t value) { id_ = value; }
+
+    const std::string& name() const { return name_; }
+    void set_name(const std::string& value) { name_ = value; }
+
+    int32_t uid() const { return uid_; }
+    void set_uid(int32_t value) { uid_ = value; }
+
+   private:
+    int32_t id_ = {};
+    std::string name_ = {};
+    int32_t uid_ = {};
+
+    // Allows to preserve unknown protobuf fields for compatibility
+    // with future versions of .proto files.
+    std::string unknown_fields_;
+  };
+
+  class PERFETTO_EXPORT DataSource {
+   public:
+    DataSource();
+    ~DataSource();
+    DataSource(DataSource&&) noexcept;
+    DataSource& operator=(DataSource&&);
+    DataSource(const DataSource&);
+    DataSource& operator=(const DataSource&);
+    bool operator==(const DataSource&) const;
+    bool operator!=(const DataSource& other) const { return !(*this == other); }
+
+    // Conversion methods from/to the corresponding protobuf types.
+    void FromProto(const perfetto::protos::TracingServiceState_DataSource&);
+    void ToProto(perfetto::protos::TracingServiceState_DataSource*) const;
+
+    const DataSourceDescriptor& descriptor() const { return descriptor_; }
+    DataSourceDescriptor* mutable_descriptor() { return &descriptor_; }
+
+    int32_t producer_id() const { return producer_id_; }
+    void set_producer_id(int32_t value) { producer_id_ = value; }
+
+   private:
+    DataSourceDescriptor descriptor_ = {};
+    int32_t producer_id_ = {};
+
+    // Allows to preserve unknown protobuf fields for compatibility
+    // with future versions of .proto files.
+    std::string unknown_fields_;
+  };
+
+  TracingServiceState();
+  ~TracingServiceState();
+  TracingServiceState(TracingServiceState&&) noexcept;
+  TracingServiceState& operator=(TracingServiceState&&);
+  TracingServiceState(const TracingServiceState&);
+  TracingServiceState& operator=(const TracingServiceState&);
+  bool operator==(const TracingServiceState&) const;
+  bool operator!=(const TracingServiceState& other) const {
+    return !(*this == other);
+  }
+
+  // Conversion methods from/to the corresponding protobuf types.
+  void FromProto(const perfetto::protos::TracingServiceState&);
+  void ToProto(perfetto::protos::TracingServiceState*) const;
+
+  int producers_size() const { return static_cast<int>(producers_.size()); }
+  const std::vector<Producer>& producers() const { return producers_; }
+  std::vector<Producer>* mutable_producers() { return &producers_; }
+  void clear_producers() { producers_.clear(); }
+  Producer* add_producers() {
+    producers_.emplace_back();
+    return &producers_.back();
+  }
+
+  int data_sources_size() const {
+    return static_cast<int>(data_sources_.size());
+  }
+  const std::vector<DataSource>& data_sources() const { return data_sources_; }
+  std::vector<DataSource>* mutable_data_sources() { return &data_sources_; }
+  void clear_data_sources() { data_sources_.clear(); }
+  DataSource* add_data_sources() {
+    data_sources_.emplace_back();
+    return &data_sources_.back();
+  }
+
+  int32_t num_sessions() const { return num_sessions_; }
+  void set_num_sessions(int32_t value) { num_sessions_ = value; }
+
+  int32_t num_sessions_started() const { return num_sessions_started_; }
+  void set_num_sessions_started(int32_t value) {
+    num_sessions_started_ = value;
+  }
+
+ private:
+  std::vector<Producer> producers_;
+  std::vector<DataSource> data_sources_;
+  int32_t num_sessions_ = {};
+  int32_t num_sessions_started_ = {};
+
+  // Allows to preserve unknown protobuf fields for compatibility
+  // with future versions of .proto files.
+  std::string unknown_fields_;
+};
+
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_TRACING_CORE_TRACING_SERVICE_STATE_H_
diff --git a/perfetto.rc b/perfetto.rc
index 8d07713..a33bd03 100644
--- a/perfetto.rc
+++ b/perfetto.rc
@@ -62,3 +62,7 @@
 on property:persist.traced.enable=0
     stop traced
     stop traced_probes
+
+# Reset the Perfetto guard rail state on boot:
+on post-fs-data
+    rm /data/misc/perfetto-traces/.guardraildata
diff --git a/protos/BUILD b/protos/BUILD
index 833822b..4a8d55f 100644
--- a/protos/BUILD
+++ b/protos/BUILD
@@ -29,10 +29,12 @@
     srcs = [
         "perfetto/common/android_log_constants.proto",
         "perfetto/common/commit_data_request.proto",
+        "perfetto/common/data_source_descriptor.proto",
         "perfetto/common/descriptor.proto",
         "perfetto/common/observable_events.proto",
         "perfetto/common/sys_stats_counters.proto",
         "perfetto/common/trace_stats.proto",
+        "perfetto/common/tracing_service_state.proto",
     ],
     has_services = 1,
     cc_api_version = 2,
@@ -59,10 +61,12 @@
     srcs = [
         "perfetto/common/android_log_constants.proto",
         "perfetto/common/commit_data_request.proto",
+        "perfetto/common/data_source_descriptor.proto",
         "perfetto/common/descriptor.proto",
         "perfetto/common/observable_events.proto",
         "perfetto/common/sys_stats_counters.proto",
         "perfetto/common/trace_stats.proto",
+        "perfetto/common/tracing_service_state.proto",
     ],
 )
 
@@ -84,7 +88,6 @@
         "perfetto/config/android/packages_list_config.proto",
         "perfetto/config/chrome/chrome_config.proto",
         "perfetto/config/data_source_config.proto",
-        "perfetto/config/data_source_descriptor.proto",
         "perfetto/config/ftrace/ftrace_config.proto",
         "perfetto/config/inode_file/inode_file_config.proto",
         "perfetto/config/power/android_power_config.proto",
@@ -149,7 +152,6 @@
         "perfetto/config/android/packages_list_config.proto",
         "perfetto/config/chrome/chrome_config.proto",
         "perfetto/config/data_source_config.proto",
-        "perfetto/config/data_source_descriptor.proto",
         "perfetto/config/ftrace/ftrace_config.proto",
         "perfetto/config/inode_file/inode_file_config.proto",
         "perfetto/config/power/android_power_config.proto",
diff --git a/protos/perfetto/common/BUILD.gn b/protos/perfetto/common/BUILD.gn
index 36a9b20..e70b03c 100644
--- a/protos/perfetto/common/BUILD.gn
+++ b/protos/perfetto/common/BUILD.gn
@@ -19,9 +19,11 @@
 common_sources = [
   "android_log_constants.proto",
   "commit_data_request.proto",
+  "data_source_descriptor.proto",
   "descriptor.proto",
   "observable_events.proto",
   "sys_stats_counters.proto",
+  "tracing_service_state.proto",
   "trace_stats.proto",
 ]
 
diff --git a/protos/perfetto/config/data_source_descriptor.proto b/protos/perfetto/common/data_source_descriptor.proto
similarity index 93%
rename from protos/perfetto/config/data_source_descriptor.proto
rename to protos/perfetto/common/data_source_descriptor.proto
index 28e59d7..08ed058 100644
--- a/protos/perfetto/config/data_source_descriptor.proto
+++ b/protos/perfetto/common/data_source_descriptor.proto
@@ -42,7 +42,4 @@
   // set if the data source writes packets that refer to previous trace
   // contents, and knows how to stop referring to the already-emitted data.
   optional bool handles_incremental_state_clear = 4;
-
-  // TODO: this should have a structure to enable reflection of the proto
-  // fields emitted (see go/perfetto-logging).
 }
diff --git a/protos/perfetto/common/tracing_service_state.proto b/protos/perfetto/common/tracing_service_state.proto
new file mode 100644
index 0000000..dd8572c
--- /dev/null
+++ b/protos/perfetto/common/tracing_service_state.proto
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 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;
+
+import "perfetto/common/data_source_descriptor.proto";
+
+// When editing this file run ./tools/gen_tracing_cpp_headers_from_protos.py
+// to reflect changes in the corresponding C++ headers.
+
+// Reports the state of the tracing service. Used to gather details about the
+// data sources connected.
+// See ConsumerPort::QueryServiceState().
+message TracingServiceState {
+  // Describes a producer process.
+  message Producer {
+    optional int32 id = 1;     // Unique ID of the producer (monotonic counter).
+    optional string name = 2;  // Typically matches the process name.
+    optional int32 uid = 3;    // Unix uid of the remote process.
+  }
+
+  // Describes a data source registered by a producer. Data sources are listed
+  // regardless of the fact that they are being used or not.
+  message DataSource {
+    // Descriptor passed by the data source when calling RegisterDataSource().
+    optional DataSourceDescriptor descriptor = 1;
+
+    // ID of the producer, as per Producer.id.
+    optional int32 producer_id = 2;
+  }
+
+  // Lists all the producers connected.
+  repeated Producer producers = 1;
+
+  // Lists the data sources available.
+  repeated DataSource data_sources = 2;
+
+  // Total number of tracing sessions.
+  optional int32 num_sessions = 3;
+
+  // Number of tracing sessions in the started state. Always <= num_sessions.
+  optional int32 num_sessions_started = 4;
+}
diff --git a/protos/perfetto/config/BUILD.gn b/protos/perfetto/config/BUILD.gn
index 2bbafba..5aec57c 100644
--- a/protos/perfetto/config/BUILD.gn
+++ b/protos/perfetto/config/BUILD.gn
@@ -35,7 +35,6 @@
     "android/packages_list_config.proto",
     "chrome/chrome_config.proto",
     "data_source_config.proto",
-    "data_source_descriptor.proto",
     "ftrace/ftrace_config.proto",
     "inode_file/inode_file_config.proto",
     "power/android_power_config.proto",
@@ -61,7 +60,6 @@
     "android/packages_list_config.proto",
     "chrome/chrome_config.proto",
     "data_source_config.proto",
-    "data_source_descriptor.proto",
     "ftrace/ftrace_config.proto",
     "inode_file/inode_file_config.proto",
     "power/android_power_config.proto",
diff --git a/protos/perfetto/ipc/consumer_port.proto b/protos/perfetto/ipc/consumer_port.proto
index 5c293ab..595c53b 100644
--- a/protos/perfetto/ipc/consumer_port.proto
+++ b/protos/perfetto/ipc/consumer_port.proto
@@ -18,6 +18,7 @@
 option optimize_for = LITE_RUNTIME;
 
 import "perfetto/common/observable_events.proto";
+import "perfetto/common/tracing_service_state.proto";
 import "perfetto/common/trace_stats.proto";
 import "perfetto/config/trace_config.proto";
 
@@ -99,7 +100,13 @@
   rpc ObserveEvents(ObserveEventsRequest)
       returns (stream ObserveEventsResponse) {}
 
-  // TODO rpc ListDataSources(), for the UI.
+  // ----------------------------------------------------
+  // All methods below have been introduced in Android R.
+  // ----------------------------------------------------
+
+  // Allows to obtain the list of data sources connected and their descriptors.
+  rpc QueryServiceState(QueryServiceStateRequest)
+      returns (stream QueryServiceStateResponse) {}
 }
 
 // Arguments for rpc EnableTracing().
@@ -213,3 +220,10 @@
 message ObserveEventsResponse {
   optional ObservableEvents events = 1;
 }
+
+// Arguments for rpc QueryServiceState
+message QueryServiceStateRequest {}
+
+message QueryServiceStateResponse {
+  optional TracingServiceState service_state = 1;
+}
diff --git a/protos/perfetto/ipc/producer_port.proto b/protos/perfetto/ipc/producer_port.proto
index e129afd..465022b 100644
--- a/protos/perfetto/ipc/producer_port.proto
+++ b/protos/perfetto/ipc/producer_port.proto
@@ -19,7 +19,7 @@
 
 import "perfetto/common/commit_data_request.proto";
 import "perfetto/config/data_source_config.proto";
-import "perfetto/config/data_source_descriptor.proto";
+import "perfetto/common/data_source_descriptor.proto";
 
 package perfetto.protos;
 
diff --git a/src/android_internal/BUILD.gn b/src/android_internal/BUILD.gn
index 142855a..5a16997 100644
--- a/src/android_internal/BUILD.gn
+++ b/src/android_internal/BUILD.gn
@@ -26,6 +26,21 @@
   ]
 }
 
+source_set("lazy_library_loader") {
+  public_deps = [
+    ":headers",
+  ]
+  deps = [
+    "../../gn:default_deps",
+    "../../src/base",
+  ]
+  sources = [
+    "lazy_library_loader.cc",
+    "lazy_library_loader.h",
+  ]
+  libs = [ "dl" ]
+}
+
 # This target proxies calls to Android internal libraries that are not part of
 # the NDK. See README.md.
 source_set("android_internal") {
diff --git a/src/android_internal/lazy_library_loader.cc b/src/android_internal/lazy_library_loader.cc
new file mode 100644
index 0000000..27c2d44
--- /dev/null
+++ b/src/android_internal/lazy_library_loader.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 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 "src/android_internal/lazy_library_loader.h"
+
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include "perfetto/base/build_config.h"
+#include "perfetto/base/logging.h"
+
+namespace perfetto {
+namespace android_internal {
+
+namespace {
+
+const char kLibName[] = "libperfetto_android_internal.so";
+
+void* LoadLibraryOnce() {
+#if !PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+  // For testing only. Allows to use the version of the .so shipped in the
+  // system (if any) with the standalone builds of perfetto. This is really
+  // crash-prone and should not be used in production. The .so doesn't have a
+  // stable ABI, hence the version of the library in the system and the code in
+  // ToT can diverge.
+  const char* env_var = getenv("PERFETTO_ENABLE_ANDROID_INTERNAL_LIB");
+  if (!env_var || strcmp(env_var, "1")) {
+    PERFETTO_ELOG(
+        "android_internal functions can be used only with in-tree builds of "
+        "perfetto.");
+    return nullptr;
+  }
+#endif
+  void* handle = dlopen(kLibName, RTLD_NOW);
+  if (!handle)
+    PERFETTO_PLOG("dlopen(%s) failed", kLibName);
+  return handle;
+}
+
+}  // namespace
+
+void* LazyLoadFunction(const char* name) {
+  // Strip the namespace qualification from the full symbol name.
+  const char* sep = strrchr(name, ':');
+  const char* function_name = sep ? sep + 1 : name;
+  static void* handle = LoadLibraryOnce();
+  if (!handle)
+    return nullptr;
+  void* fn = dlsym(handle, function_name);
+  if (!fn)
+    PERFETTO_PLOG("dlsym(%s) failed", function_name);
+  return fn;
+}
+
+}  // namespace android_internal
+}  // namespace perfetto
diff --git a/src/android_internal/lazy_library_loader.h b/src/android_internal/lazy_library_loader.h
new file mode 100644
index 0000000..22b1587
--- /dev/null
+++ b/src/android_internal/lazy_library_loader.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef SRC_ANDROID_INTERNAL_LAZY_LIBRARY_LOADER_H_
+#define SRC_ANDROID_INTERNAL_LAZY_LIBRARY_LOADER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace perfetto {
+namespace android_internal {
+
+// Dynamically loads (once) the libperfetto_android_internal.so and looks up the
+// given symbol name. It never unloads the library once loaded. Doing so is very
+// bug-prone (see b/137280403).
+// |name| can be either a symbol name (e.g. DoFoo) or a (partially or fully)
+// qualified name (e.g., android_internal::DoFoo). In the latter case the
+// namespace is dropped only the symbol name is retained (in other words this
+// function assumes all symbols are declared as extern "C").
+void* LazyLoadFunction(const char* name);
+
+// Convenience wrapper to avoid the reinterpret_cast boilerplate. Boils down to:
+// FunctionType name = reinterpret_cast<FunctionType>(LazyLoadFunction(...)).
+// Can be used both for member fields and local variables.
+#define PERFETTO_LAZY_LOAD(FUNCTION, VAR_NAME)                          \
+  decltype(&FUNCTION) VAR_NAME = reinterpret_cast<decltype(&FUNCTION)>( \
+      ::perfetto::android_internal::LazyLoadFunction(#FUNCTION))
+
+}  // namespace android_internal
+}  // namespace perfetto
+
+#endif  // SRC_ANDROID_INTERNAL_LAZY_LIBRARY_LOADER_H_
diff --git a/src/perfetto_cmd/BUILD.gn b/src/perfetto_cmd/BUILD.gn
index 6f1c27b..0f82514 100644
--- a/src/perfetto_cmd/BUILD.gn
+++ b/src/perfetto_cmd/BUILD.gn
@@ -27,7 +27,7 @@
     "../../gn:zlib_deps",
     "../../protos/perfetto/common:lite",
     "../../protos/perfetto/config:lite",
-    "../android_internal:headers",
+    "../android_internal:lazy_library_loader",
     "../base",
     "../protozero",
     "../tracing:ipc",
diff --git a/src/perfetto_cmd/packet_writer.cc b/src/perfetto_cmd/packet_writer.cc
index d2efa13..457ed94 100644
--- a/src/perfetto_cmd/packet_writer.cc
+++ b/src/perfetto_cmd/packet_writer.cc
@@ -229,7 +229,7 @@
 
 void ZipPacketWriter::Deflate(const uint8_t* ptr, size_t size) {
   PERFETTO_CHECK(is_compressing_);
-  stream_.next_in = ptr;
+  stream_.next_in = const_cast<uint8_t*>(ptr);
   stream_.avail_in = static_cast<unsigned int>(size);
   CheckEq(deflate(&stream_, Z_NO_FLUSH), Z_OK);
   PERFETTO_CHECK(stream_.avail_in == 0);
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index e1f71dd..1d73166 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -16,7 +16,6 @@
 
 #include "src/perfetto_cmd/perfetto_cmd.h"
 
-#include <dlfcn.h>
 #include <fcntl.h>
 #include <getopt.h>
 #include <signal.h>
@@ -35,6 +34,7 @@
 #include "perfetto/base/string_view.h"
 #include "perfetto/base/time.h"
 #include "perfetto/base/utils.h"
+#include "perfetto/common/tracing_service_state.pb.h"
 #include "perfetto/config/trace_config.pb.h"
 #include "perfetto/protozero/proto_utils.h"
 #include "perfetto/traced/traced.h"
@@ -43,6 +43,7 @@
 #include "perfetto/tracing/core/data_source_descriptor.h"
 #include "perfetto/tracing/core/trace_config.h"
 #include "perfetto/tracing/core/trace_packet.h"
+#include "perfetto/tracing/core/tracing_service_state.h"
 #include "src/perfetto_cmd/config.h"
 #include "src/perfetto_cmd/packet_writer.h"
 #include "src/perfetto_cmd/pbtxt_to_pb.h"
@@ -59,6 +60,7 @@
 #include <utils/StrongPointer.h>
 
 #include "src/android_internal/incident_service.h"
+#include "src/android_internal/lazy_library_loader.h"
 #endif  // PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
 
 namespace perfetto {
@@ -66,6 +68,8 @@
 
 perfetto::PerfettoCmd* g_consumer_cmd;
 
+uint32_t kOnTraceDataTimeoutMs = 3000;
+
 class LoggingErrorReporter : public ErrorReporter {
  public:
   LoggingErrorReporter(std::string file_name, const char* config)
@@ -126,24 +130,17 @@
 
 #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
 static bool StartIncidentReport(const TraceConfig::IncidentReportConfig& cfg) {
-  using ScopedDlHandle = base::ScopedResource<void*, dlclose, nullptr>;
-
-  static const char kLibName[] = "libperfetto_android_internal.so";
-  ScopedDlHandle handle(dlopen(kLibName, RTLD_NOW));
-  PERFETTO_CHECK(handle);
-
-  void* fn = dlsym(*handle, "StartIncidentReport");
-  PERFETTO_CHECK(fn);
-  auto start_incident =
-      reinterpret_cast<decltype(&android_internal::StartIncidentReport)>(fn);
-
-  return start_incident(cfg.destination_package().c_str(),
-                        cfg.destination_class().c_str(), cfg.privacy_level());
+  PERFETTO_LAZY_LOAD(android_internal::StartIncidentReport, start_incident_fn);
+  if (!start_incident_fn)
+    return false;
+  return start_incident_fn(cfg.destination_package().c_str(),
+                           cfg.destination_class().c_str(),
+                           cfg.privacy_level());
 }
 #else
 static bool StartIncidentReport(const TraceConfig::IncidentReportConfig&) {
   PERFETTO_FATAL("should not be called");
-};
+}
 #endif
 
 }  // namespace
@@ -167,13 +164,21 @@
 int PerfettoCmd::PrintUsage(const char* argv0) {
   PERFETTO_ELOG(R"(
 Usage: %s
-  --background     -d      : Exits immediately and continues tracing in background
+  --background     -d      : Exits immediately and continues tracing in
+                             background
   --config         -c      : /path/to/trace/config/file or - for stdin
   --out            -o      : /path/to/out/trace/file or - for stdout
   --dropbox           TAG  : Upload trace into DropBox using tag TAG
-  --no-guardrails          : Ignore guardrails triggered when using --dropbox (for testing).
-  --txt                    : Parse config as pbtxt. Not a stable API. Not for production use.
-  --reset-guardrails       : Resets the state of the guardails and exits (for testing).
+  --no-guardrails          : Ignore guardrails triggered when using --dropbox
+                             (for testing).
+  --txt                    : Parse config as pbtxt. Not for production use.
+                             Not a stable API.
+  --reset-guardrails       : Resets the state of the guardails and exits
+                             (for testing).
+  --query                  : Queries the service state and prints it as
+                             human-readable text.
+  --query-raw              : Like --query, but prints raw proto-encoded bytes
+                             of tracing_service_state.proto.
   --help           -h
 
 
@@ -216,6 +221,8 @@
     OPT_ATTACH,
     OPT_IS_DETACHED,
     OPT_STOP,
+    OPT_QUERY,
+    OPT_QUERY_RAW,
   };
   static const struct option long_options[] = {
       {"help", no_argument, nullptr, 'h'},
@@ -238,6 +245,8 @@
       {"is_detached", required_argument, nullptr, OPT_IS_DETACHED},
       {"stop", no_argument, nullptr, OPT_STOP},
       {"app", required_argument, nullptr, OPT_ATRACE_APP},
+      {"query", no_argument, nullptr, OPT_QUERY},
+      {"query-raw", no_argument, nullptr, OPT_QUERY_RAW},
       {nullptr, 0, nullptr, 0}};
 
   int option_index = 0;
@@ -391,6 +400,17 @@
       continue;
     }
 
+    if (option == OPT_QUERY) {
+      query_service_ = true;
+      continue;
+    }
+
+    if (option == OPT_QUERY_RAW) {
+      query_service_ = true;
+      query_service_output_raw_ = true;
+      continue;
+    }
+
     return PrintUsage(argv[0]);
   }
 
@@ -399,6 +419,11 @@
     config_options.categories.push_back(argv[i]);
   }
 
+  if (query_service_ && (is_detach() || is_attach() || background)) {
+    PERFETTO_ELOG("--query cannot be combined with any other argument");
+    return 1;
+  }
+
   if (is_detach() && is_attach()) {
     PERFETTO_ELOG("--attach and --detach are mutually exclusive");
     return 1;
@@ -423,9 +448,10 @@
   perfetto::protos::TraceConfig trace_config_proto;
   std::vector<std::string> triggers_to_activate;
   bool parsed = false;
-  if (is_attach()) {
+  const bool will_trace = !is_attach() && !query_service_;
+  if (!will_trace) {
     if ((!trace_config_raw.empty() || has_config_options)) {
-      PERFETTO_ELOG("Cannot specify a trace config with --attach");
+      PERFETTO_ELOG("Cannot specify a trace config with this option");
       return 1;
     }
   } else if (has_config_options) {
@@ -455,7 +481,7 @@
     *trace_config_proto.mutable_statsd_metadata() = std::move(statsd_metadata);
     trace_config_->FromProto(trace_config_proto);
     trace_config_raw.clear();
-  } else if (!is_attach()) {
+  } else if (will_trace) {
     PERFETTO_ELOG("The trace config is invalid, bailing out.");
     return 1;
   }
@@ -489,10 +515,10 @@
   }
 
   bool open_out_file = true;
-  if (is_attach()) {
+  if (!will_trace) {
     open_out_file = false;
     if (!trace_out_path_.empty() || !dropbox_tag_.empty()) {
-      PERFETTO_ELOG("Can't pass an --out file (or --dropbox) to --attach");
+      PERFETTO_ELOG("Can't pass an --out file (or --dropbox) with this option");
       return 1;
     }
   } else if (!triggers_to_activate.empty()) {
@@ -544,16 +570,24 @@
   // the options.
   if (!triggers_to_activate.empty()) {
     bool finished_with_success = false;
-    TriggerProducer producer(&task_runner_,
-                             [this, &finished_with_success](bool success) {
-                               finished_with_success = success;
-                               task_runner_.Quit();
-                             },
-                             &triggers_to_activate);
+    TriggerProducer producer(
+        &task_runner_,
+        [this, &finished_with_success](bool success) {
+          finished_with_success = success;
+          task_runner_.Quit();
+        },
+        &triggers_to_activate);
     task_runner_.Run();
     return finished_with_success ? 0 : 1;
   }
 
+  if (query_service_) {
+    consumer_endpoint_ =
+        ConsumerIPCClient::Connect(GetConsumerSocket(), this, &task_runner_);
+    task_runner_.Run();
+    return 1;  // We can legitimately get here if the service disconnects.
+  }
+
   if (trace_config_->compression_type() ==
       perfetto::TraceConfig::COMPRESSION_TYPE_DEFLATE) {
     if (packet_writer_) {
@@ -581,6 +615,16 @@
     return 1;
   }
 
+  expected_duration_ms_ = trace_config_->duration_ms();
+  if (!expected_duration_ms_) {
+    uint32_t timeout_ms = trace_config_->trigger_config().trigger_timeout_ms();
+    uint32_t max_stop_delay_ms = 0;
+    for (const auto& trigger : trace_config_->trigger_config().triggers()) {
+      max_stop_delay_ms = std::max(max_stop_delay_ms, trigger.stop_delay_ms());
+    }
+    expected_duration_ms_ = timeout_ms + max_stop_delay_ms;
+  }
+
   if (!limiter.ShouldTrace(args))
     return 1;
 
@@ -594,14 +638,28 @@
 }
 
 void PerfettoCmd::OnConnect() {
+  if (query_service_) {
+    consumer_endpoint_->QueryServiceState(
+        [this](bool success, const TracingServiceState& svc_state) {
+          PrintServiceState(success, svc_state);
+          fflush(stdout);
+          exit(success ? 0 : 1);
+        });
+    return;
+  }
+
   if (is_attach()) {
     consumer_endpoint_->Attach(attach_key_);
     return;
   }
 
-  PERFETTO_LOG(
-      "Connected to the Perfetto traced service, starting tracing for %d ms",
-      trace_config_->duration_ms());
+  if (expected_duration_ms_) {
+    PERFETTO_LOG("Connected to the Perfetto traced service, TTL: %ds",
+                 (expected_duration_ms_ + 999) / 1000);
+  } else {
+    PERFETTO_LOG("Connected to the Perfetto traced service, starting tracing");
+  }
+
   PERFETTO_DCHECK(trace_config_);
   trace_config_->set_enable_extra_guardrails(!dropbox_tag_.empty());
 
@@ -617,9 +675,9 @@
   }
 
   // Failsafe mechanism to avoid waiting indefinitely if the service hangs.
-  if (trace_config_->duration_ms()) {
-    uint32_t trace_timeout = trace_config_->duration_ms() + 10000 +
-                             trace_config_->flush_timeout_ms();
+  if (expected_duration_ms_) {
+    uint32_t trace_timeout =
+        expected_duration_ms_ + 60000 + trace_config_->flush_timeout_ms();
     task_runner_.PostDelayedTask(std::bind(&PerfettoCmd::OnTimeout, this),
                                  trace_timeout);
   }
@@ -635,7 +693,20 @@
   task_runner_.Quit();
 }
 
+void PerfettoCmd::CheckTraceDataTimeout() {
+  if (trace_data_timeout_armed_) {
+    PERFETTO_ELOG("Timed out while waiting for OnTraceData, aborting");
+    FinalizeTraceAndExit();
+  }
+  trace_data_timeout_armed_ = true;
+  task_runner_.PostDelayedTask(
+      std::bind(&PerfettoCmd::CheckTraceDataTimeout, this),
+      kOnTraceDataTimeoutMs);
+}
+
 void PerfettoCmd::OnTraceData(std::vector<TracePacket> packets, bool has_more) {
+  trace_data_timeout_armed_ = false;
+
   if (!packet_writer_->WritePackets(packets)) {
     PERFETTO_ELOG("Failed to write packets");
     FinalizeTraceAndExit();
@@ -651,6 +722,10 @@
     // already all the packets.
     return FinalizeTraceAndExit();
   }
+
+  trace_data_timeout_armed_ = false;
+  CheckTraceDataTimeout();
+
   // This will cause a bunch of OnTraceData callbacks. The last one will
   // save the file and exit.
   consumer_endpoint_->ReadBuffers();
@@ -683,17 +758,26 @@
   // Otherwise, write to Dropbox unless there's a special override in the
   // incident report config.
   if (!trace_config_->incident_report_config().skip_dropbox()) {
-    SaveOutputToDropboxOrCrash();
+    if (bytes_written_ == 0) {
+      PERFETTO_LOG("Skipping write to dropbox. Empty trace.");
+    } else {
+      SaveOutputToDropboxOrCrash();
+    }
   }
 
   // Optionally save the trace as an incident. This is either in addition to, or
   // instead of, the Dropbox write.
   if (!trace_config_->incident_report_config().destination_package().empty()) {
-    SaveOutputToIncidentTraceOrCrash();
+    if (bytes_written_ == 0) {
+      PERFETTO_LOG("Skipping incident report. Empty trace.");
+    } else {
+      SaveOutputToIncidentTraceOrCrash();
 
-    // Ask incidentd to create a report, which will read the file we just wrote.
-    PERFETTO_CHECK(
-        StartIncidentReport(trace_config_->incident_report_config()));
+      // Ask incidentd to create a report, which will read the file we just
+      // wrote.
+      PERFETTO_CHECK(
+          StartIncidentReport(trace_config_->incident_report_config()));
+    }
   }
 
   did_process_full_trace_ = true;
@@ -702,10 +786,6 @@
 
 void PerfettoCmd::SaveOutputToDropboxOrCrash() {
 #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
-  if (bytes_written_ == 0) {
-    PERFETTO_LOG("Skipping write to dropbox. Empty trace.");
-    return;
-  }
   android::sp<android::os::DropBoxManager> dropbox =
       new android::os::DropBoxManager();
   PERFETTO_CHECK(fseek(*trace_out_stream_, 0, SEEK_SET) == 0);
@@ -730,16 +810,12 @@
 }
 
 // Open a staging file (unlinking the previous instance), copy the trace
-// contents over, then rename to a final hardcoded path. Such tracing sessions
-// should not normally overlap. We do not use unique unique filenames to avoid
-// creating an unbounded amount of files in case of errors.
+// contents over, then rename to a final hardcoded path (known to incidentd).
+// Such tracing sessions should not normally overlap. We do not use unique
+// unique filenames to avoid creating an unbounded amount of files in case of
+// errors.
 void PerfettoCmd::SaveOutputToIncidentTraceOrCrash() {
 #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
-  if (bytes_written_ == 0) {
-    PERFETTO_LOG("Skipping incident report. Empty trace.");
-    return;
-  }
-
   PERFETTO_CHECK(unlink(kTempIncidentTraceLocation) == 0 || errno == ENOENT);
 
   // SELinux constrains the set of readers.
@@ -865,6 +941,43 @@
   // TODO(eseckler): Support GetTraceStats().
 }
 
+void PerfettoCmd::PrintServiceState(bool success,
+                                    const TracingServiceState& svc_state) {
+  if (!success) {
+    PERFETTO_ELOG("Failed to query the service state");
+    return;
+  }
+
+  if (query_service_output_raw_) {
+    protos::TracingServiceState proto;
+    svc_state.ToProto(&proto);
+    std::string str = proto.SerializeAsString();
+    fwrite(str.data(), 1, str.size(), stdout);
+    return;
+  }
+
+  printf("Not meant for machine consumption. Use --query-raw for scripts.\n");
+
+  for (const auto& producer : svc_state.producers()) {
+    printf("producers: {\n");
+    printf("  id: %d\n", producer.id());
+    printf("  name: \"%s\" \n", producer.name().c_str());
+    printf("  uid: %d \n", producer.uid());
+    printf("}\n");
+  }
+
+  for (const auto& ds : svc_state.data_sources()) {
+    printf("data_sources: {\n");
+    printf("  producer_id: %d\n", ds.producer_id());
+    printf("  descriptor: {\n");
+    printf("    name: \"%s\"\n", ds.descriptor().name().c_str());
+    printf("  }\n");
+    printf("}\n");
+  }
+  printf("num_sessions: %d\n", svc_state.num_sessions());
+  printf("num_sessions_started: %d\n", svc_state.num_sessions_started());
+}
+
 void PerfettoCmd::OnObservableEvents(
     const ObservableEvents& /*observable_events*/) {}
 
diff --git a/src/perfetto_cmd/perfetto_cmd.h b/src/perfetto_cmd/perfetto_cmd.h
index 2a1453e..7a98f09 100644
--- a/src/perfetto_cmd/perfetto_cmd.h
+++ b/src/perfetto_cmd/perfetto_cmd.h
@@ -72,13 +72,24 @@
   void SetupCtrlCSignalHandler();
   void FinalizeTraceAndExit();
   int PrintUsage(const char* argv0);
+  void PrintServiceState(bool success, const TracingServiceState&);
   void OnTimeout();
   bool is_detach() const { return !detach_key_.empty(); }
   bool is_attach() const { return !attach_key_.empty(); }
+
+  // Once we call ReadBuffers we expect one or more calls to OnTraceData
+  // with the last call having |has_more| set to false. However we should
+  // gracefully handle the service failing to ever call OnTraceData or
+  // setting |has_more| incorrectly. To do this we maintain a timeout
+  // which finalizes and exits the client if we don't receive OnTraceData
+  // within OnTraceDataTimeoutMs of when we expected to.
+  void CheckTraceDataTimeout();
+
   void SaveOutputToDropboxOrCrash();
   void SaveOutputToIncidentTraceOrCrash();
 
   PlatformTaskRunner task_runner_;
+
   std::unique_ptr<perfetto::TracingService::ConsumerEndpoint>
       consumer_endpoint_;
   std::unique_ptr<TraceConfig> trace_config_;
@@ -95,6 +106,12 @@
   std::string attach_key_;
   bool stop_trace_once_attached_ = false;
   bool redetach_once_attached_ = false;
+  bool query_service_ = false;
+  bool query_service_output_raw_ = false;
+
+  // How long we expect to trace for or 0 if the trace is indefinite.
+  uint32_t expected_duration_ms_ = 0;
+  bool trace_data_timeout_armed_ = false;
 };
 
 }  // namespace perfetto
diff --git a/src/perfetto_cmd/rate_limiter.cc b/src/perfetto_cmd/rate_limiter.cc
index 3b018bc..56f34c4 100644
--- a/src/perfetto_cmd/rate_limiter.cc
+++ b/src/perfetto_cmd/rate_limiter.cc
@@ -106,7 +106,8 @@
   }
 
   // If we've uploaded in the last 5mins we shouldn't trace now.
-  if ((now_in_s - state_.last_trace_timestamp()) < kCooldownInSeconds) {
+  if (state_.last_trace_timestamp() != 0 &&
+      (now_in_s - state_.last_trace_timestamp()) < kCooldownInSeconds) {
     PERFETTO_ELOG("Guardrail: Uploaded to DropBox in the last 5mins.");
     if (!args.ignore_guardrails)
       return false;
diff --git a/src/profiling/memory/bookkeeping.cc b/src/profiling/memory/bookkeeping.cc
index f4c4ec2..04cc33d 100644
--- a/src/profiling/memory/bookkeeping.cc
+++ b/src/profiling/memory/bookkeeping.cc
@@ -72,7 +72,7 @@
       GlobalCallstackTrie::Node* node = callsites_->CreateCallsite(callstack);
       alloc.total_size = size;
       alloc.sequence_number = sequence_number;
-      alloc.callstack_allocations = MaybeCreateCallstackAllocations(node);
+      alloc.SetCallstackAllocations(MaybeCreateCallstackAllocations(node));
     }
   } else {
     GlobalCallstackTrie::Node* node = callsites_->CreateCallsite(callstack);
diff --git a/src/profiling/memory/bookkeeping.h b/src/profiling/memory/bookkeeping.h
index 65944e2..fe706ca 100644
--- a/src/profiling/memory/bookkeeping.h
+++ b/src/profiling/memory/bookkeeping.h
@@ -306,8 +306,8 @@
 
   struct Allocation {
     Allocation(uint64_t size, uint64_t seq, CallstackAllocations* csa)
-        : total_size(size), sequence_number(seq), callstack_allocations(csa) {
-      callstack_allocations->allocs++;
+        : total_size(size), sequence_number(seq) {
+      SetCallstackAllocations(csa);
     }
 
     Allocation() = default;
@@ -315,28 +315,39 @@
     Allocation(Allocation&& other) noexcept {
       total_size = other.total_size;
       sequence_number = other.sequence_number;
-      callstack_allocations = other.callstack_allocations;
-      other.callstack_allocations = nullptr;
+      callstack_allocations_ = other.callstack_allocations_;
+      other.callstack_allocations_ = nullptr;
     }
 
     void AddToCallstackAllocations() {
-      callstack_allocations->allocation_count++;
-      callstack_allocations->allocated += total_size;
+      callstack_allocations_->allocation_count++;
+      callstack_allocations_->allocated += total_size;
     }
 
     void SubtractFromCallstackAllocations() {
-      callstack_allocations->free_count++;
-      callstack_allocations->freed += total_size;
+      callstack_allocations_->free_count++;
+      callstack_allocations_->freed += total_size;
     }
 
-    ~Allocation() {
-      if (callstack_allocations)
-        callstack_allocations->allocs--;
+    ~Allocation() { SetCallstackAllocations(nullptr); }
+
+    void SetCallstackAllocations(CallstackAllocations* callstack_allocations) {
+      if (callstack_allocations_)
+        callstack_allocations_->allocs--;
+      callstack_allocations_ = callstack_allocations;
+      if (callstack_allocations_)
+        callstack_allocations_->allocs++;
+    }
+
+    CallstackAllocations* callstack_allocations() const {
+      return callstack_allocations_;
     }
 
     uint64_t total_size;
     uint64_t sequence_number;
-    CallstackAllocations* callstack_allocations;
+
+   private:
+    CallstackAllocations* callstack_allocations_ = nullptr;
   };
 
   struct PendingOperation {
diff --git a/src/profiling/memory/client.cc b/src/profiling/memory/client.cc
index 59c7e20..37453d1 100644
--- a/src/profiling/memory/client.cc
+++ b/src/profiling/memory/client.cc
@@ -202,10 +202,7 @@
   }
 
   PERFETTO_DCHECK(client_config.interval >= 1);
-  // TODO(fmayer): Always make this nonblocking.
-  // This is so that without block_client, we get the old behaviour that rate
-  // limits using the blocking socket. We do not want to change that for Q.
-  sock.SetBlocking(!client_config.block_client);
+  sock.SetBlocking(false);
   Sampler sampler{client_config.interval};
   // note: the shared_ptr will retain a copy of the unhooked_allocator
   return std::allocate_shared<Client>(unhooked_allocator, std::move(sock),
@@ -368,10 +365,12 @@
 }
 
 bool Client::SendControlSocketByte() {
-  // TODO(fmayer): Fix the special casing that only block_client uses a
-  // nonblocking socket.
+  // If base::IsAgain(errno), the socket buffer is full, so the service will
+  // pick up the notification even without adding another byte.
+  // In other error cases (usually EPIPE) we want to disconnect, because that
+  // is how the service signals the tracing session was torn down.
   if (sock_.Send(kSingleByte, sizeof(kSingleByte)) == -1 &&
-      (!client_config_.block_client || !base::IsAgain(errno))) {
+      !base::IsAgain(errno)) {
     PERFETTO_PLOG("Failed to send control socket byte.");
     return false;
   }
diff --git a/src/profiling/memory/malloc_hooks.cc b/src/profiling/memory/malloc_hooks.cc
index 6070a03..904c6c1 100644
--- a/src/profiling/memory/malloc_hooks.cc
+++ b/src/profiling/memory/malloc_hooks.cc
@@ -467,7 +467,7 @@
 void* HEAPPROFD_ADD_PREFIX(_calloc)(size_t nmemb, size_t size) {
   const MallocDispatch* dispatch = GetDispatch();
   void* addr = dispatch->calloc(nmemb, size);
-  MaybeSampleAllocation(size, addr);
+  MaybeSampleAllocation(nmemb * size, addr);
   return addr;
 }
 
@@ -501,6 +501,17 @@
 // sure that the address is not reused before we've processed the deallocation
 // (which includes assigning a sequence id to it).
 void HEAPPROFD_ADD_PREFIX(_free)(void* pointer) {
+  // free on a nullptr is valid but has no effect. Short circuit here, for
+  // various advantages:
+  // * More efficient
+  // * Notably printf calls free(nullptr) even when it is used in a way
+  //   malloc-free way, as it unconditionally frees the pointer even if
+  //   it was never written to.
+  //   Short circuiting here makes it less likely to accidentally build
+  //   infinite recursion.
+  if (pointer == nullptr)
+    return;
+
   const MallocDispatch* dispatch = GetDispatch();
   std::shared_ptr<perfetto::profiling::Client> client;
   {
diff --git a/src/profiling/memory/unwinding.cc b/src/profiling/memory/unwinding.cc
index cc79477..31b9a9c 100644
--- a/src/profiling/memory/unwinding.cc
+++ b/src/profiling/memory/unwinding.cc
@@ -314,9 +314,7 @@
     shmem.EndRead(std::move(buf));
     // Reparsing takes time, so process the rest in a new batch to avoid timing
     // out.
-    // TODO(fmayer): Do not special case blocking mode.
-    if (client_data.client_config.block_client &&
-        reparses_before < client_data.metadata.reparses) {
+    if (reparses_before < client_data.metadata.reparses) {
       repost_task = true;
       break;
     }
diff --git a/src/traced/probes/ftrace/BUILD.gn b/src/traced/probes/ftrace/BUILD.gn
index 3903a20..5ddf80c 100644
--- a/src/traced/probes/ftrace/BUILD.gn
+++ b/src/traced/probes/ftrace/BUILD.gn
@@ -108,13 +108,13 @@
     "../../../../protos/perfetto/trace/ftrace:zero",
     "../../../tracing",
   ]
-  libs = [ "dl" ]  # for dlopen()
   deps = [
     ":format_parser",
     "..:data_source",
     "../../../../gn:default_deps",
     "../../../../include/perfetto/traced",
     "../../../android_internal:headers",
+    "../../../android_internal:lazy_library_loader",
     "../../../base",
     "../../../protozero",
   ]
diff --git a/src/traced/probes/ftrace/atrace_hal_wrapper.cc b/src/traced/probes/ftrace/atrace_hal_wrapper.cc
index 6e3f29f..11cdd89 100644
--- a/src/traced/probes/ftrace/atrace_hal_wrapper.cc
+++ b/src/traced/probes/ftrace/atrace_hal_wrapper.cc
@@ -15,9 +15,8 @@
  */
 #include "src/traced/probes/ftrace/atrace_hal_wrapper.h"
 
-#include <dlfcn.h>
-
 #include "src/android_internal/atrace_hal.h"
+#include "src/android_internal/lazy_library_loader.h"
 
 namespace perfetto {
 
@@ -26,22 +25,7 @@
 }
 
 struct AtraceHalWrapper::DynamicLibLoader {
-  using ScopedDlHandle = base::ScopedResource<void*, dlclose, nullptr>;
-
-  DynamicLibLoader() {
-    static const char kLibName[] = "libperfetto_android_internal.so";
-    handle_.reset(dlopen(kLibName, RTLD_NOW));
-    if (!handle_) {
-      PERFETTO_PLOG("dlopen(%s) failed", kLibName);
-      return;
-    }
-    void* fn = dlsym(*handle_, "GetCategories");
-    if (!fn) {
-      PERFETTO_PLOG("dlsym(GetCategories) failed");
-      return;
-    }
-    get_categories_ = reinterpret_cast<decltype(get_categories_)>(fn);
-  }
+  PERFETTO_LAZY_LOAD(android_internal::GetCategories, get_categories_);
 
   std::vector<android_internal::TracingVendorCategory> GetCategories() {
     if (!get_categories_)
@@ -54,10 +38,6 @@
     categories.resize(num_cat);
     return categories;
   }
-
- private:
-  decltype(&android_internal::GetCategories) get_categories_ = nullptr;
-  ScopedDlHandle handle_;
 };
 
 AtraceHalWrapper::AtraceHalWrapper() {
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.cc b/src/traced/probes/ftrace/ftrace_config_muxer.cc
index 4dbf313..ee721a7 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.cc
@@ -173,6 +173,7 @@
         events.insert(GroupAndName("clk", "clk_disable"));
         events.insert(GroupAndName("clk", "clk_enable"));
         events.insert(GroupAndName("power", "cpu_frequency_limits"));
+        events.insert(GroupAndName("power", "suspend_resume"));
         AddEventGroup(table, "msm_bus", &events);
         continue;
       }
diff --git a/src/traced/probes/power/BUILD.gn b/src/traced/probes/power/BUILD.gn
index fda4f12..358f6b4 100644
--- a/src/traced/probes/power/BUILD.gn
+++ b/src/traced/probes/power/BUILD.gn
@@ -16,13 +16,12 @@
   public_deps = [
     "../../../tracing",
   ]
-  libs = [ "dl" ]  # for dlopen()
   deps = [
     "..:data_source",
     "../../../../gn:default_deps",
     "../../../../include/perfetto/traced",
     "../../../../protos/perfetto/trace/power:zero",
-    "../../../android_internal:headers",
+    "../../../android_internal:lazy_library_loader",
     "../../../base",
   ]
   sources = [
diff --git a/src/traced/probes/power/android_power_data_source.cc b/src/traced/probes/power/android_power_data_source.cc
index 43b2422..9a2c087 100644
--- a/src/traced/probes/power/android_power_data_source.cc
+++ b/src/traced/probes/power/android_power_data_source.cc
@@ -16,8 +16,6 @@
 
 #include "src/traced/probes/power/android_power_data_source.h"
 
-#include <dlfcn.h>
-
 #include <vector>
 
 #include "perfetto/base/logging.h"
@@ -29,6 +27,7 @@
 #include "perfetto/tracing/core/trace_packet.h"
 #include "perfetto/tracing/core/trace_writer.h"
 #include "src/android_internal/health_hal.h"
+#include "src/android_internal/lazy_library_loader.h"
 #include "src/android_internal/power_stats_hal.h"
 
 #include "perfetto/trace/power/battery_counters.pbzero.h"
@@ -42,40 +41,13 @@
 constexpr size_t kMaxNumRails = 32;
 }  // namespace
 
-// Dynamically loads / unloads the libperfetto_android_internal.so library which
+// Dynamically loads the libperfetto_android_internal.so library which
 // allows to proxy calls to android hwbinder in in-tree builds.
 struct AndroidPowerDataSource::DynamicLibLoader {
-  using ScopedDlHandle = base::ScopedResource<void*, dlclose, nullptr>;
-
-  DynamicLibLoader() {
-    static const char kLibName[] = "libperfetto_android_internal.so";
-    handle_.reset(dlopen(kLibName, RTLD_NOW));
-    if (!handle_) {
-      PERFETTO_PLOG("dlopen(%s) failed", kLibName);
-      return;
-    }
-    void* fn = dlsym(*handle_, "GetBatteryCounter");
-    if (!fn) {
-      PERFETTO_PLOG("dlsym(GetBatteryCounter) failed");
-      return;
-    }
-    get_battery_counter_ = reinterpret_cast<decltype(get_battery_counter_)>(fn);
-
-    fn = dlsym(*handle_, "GetAvailableRails");
-    if (!fn) {
-      PERFETTO_PLOG("dlsym(GetAvailableRails) failed");
-      return;
-    }
-    get_available_rails_ = reinterpret_cast<decltype(get_available_rails_)>(fn);
-
-    fn = dlsym(*handle_, "GetRailEnergyData");
-    if (!fn) {
-      PERFETTO_PLOG("dlsym(GetRailEnergyData) failed");
-      return;
-    }
-    get_rail_energy_data_ =
-        reinterpret_cast<decltype(get_rail_energy_data_)>(fn);
-  }
+  PERFETTO_LAZY_LOAD(android_internal::GetBatteryCounter, get_battery_counter_);
+  PERFETTO_LAZY_LOAD(android_internal::GetAvailableRails, get_available_rails_);
+  PERFETTO_LAZY_LOAD(android_internal::GetRailEnergyData,
+                     get_rail_energy_data_);
 
   base::Optional<int64_t> GetCounter(android_internal::BatteryCounter counter) {
     if (!get_battery_counter_)
@@ -108,15 +80,6 @@
     energy_data.resize(num_rails);
     return energy_data;
   }
-
-  bool is_loaded() const { return !!handle_; }
-
- private:
-  decltype(&android_internal::GetBatteryCounter) get_battery_counter_ = nullptr;
-  decltype(&android_internal::GetAvailableRails) get_available_rails_ = nullptr;
-  decltype(&android_internal::GetRailEnergyData) get_rail_energy_data_ =
-      nullptr;
-  ScopedDlHandle handle_;
 };
 
 AndroidPowerDataSource::AndroidPowerDataSource(
@@ -165,8 +128,6 @@
 
 void AndroidPowerDataSource::Start() {
   lib_.reset(new DynamicLibLoader());
-  if (!lib_->is_loaded())
-    return;
   Tick();
 }
 
diff --git a/src/tracing/BUILD.gn b/src/tracing/BUILD.gn
index 301b9e5..cd9823d 100644
--- a/src/tracing/BUILD.gn
+++ b/src/tracing/BUILD.gn
@@ -69,6 +69,7 @@
     "core/trace_writer_impl.h",
     "core/tracing_service_impl.cc",
     "core/tracing_service_impl.h",
+    "core/tracing_service_state.cc",
     "core/virtual_destructors.cc",
   ]
 }
diff --git a/src/tracing/core/data_source_descriptor.cc b/src/tracing/core/data_source_descriptor.cc
index 1ab58d4..015c590 100644
--- a/src/tracing/core/data_source_descriptor.cc
+++ b/src/tracing/core/data_source_descriptor.cc
@@ -18,7 +18,7 @@
  * AUTOGENERATED - DO NOT EDIT
  *******************************************************************************
  * This file has been generated from the protobuf message
- * perfetto/config/data_source_descriptor.proto
+ * perfetto/common/data_source_descriptor.proto
  * by
  * ../../tools/proto_to_cpp/proto_to_cpp.cc.
  * If you need to make changes here, change the .proto file and then run
@@ -27,7 +27,7 @@
 
 #include "perfetto/tracing/core/data_source_descriptor.h"
 
-#include "perfetto/config/data_source_descriptor.pb.h"
+#include "perfetto/common/data_source_descriptor.pb.h"
 
 namespace perfetto {
 
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index db27f46..1f32db6 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -48,6 +48,7 @@
 #include "perfetto/tracing/core/shared_memory_abi.h"
 #include "perfetto/tracing/core/trace_packet.h"
 #include "perfetto/tracing/core/trace_writer.h"
+#include "perfetto/tracing/core/tracing_service_state.h"
 #include "src/tracing/core/packet_stream_validator.h"
 #include "src/tracing/core/shared_memory_arbiter_impl.h"
 #include "src/tracing/core/trace_buffer.h"
@@ -1375,7 +1376,7 @@
 // Note: when this is called to write into a file passed when starting tracing
 // |consumer| will be == nullptr (as opposite to the case of a consumer asking
 // to send the trace data back over IPC).
-void TracingServiceImpl::ReadBuffers(TracingSessionID tsid,
+bool TracingServiceImpl::ReadBuffers(TracingSessionID tsid,
                                      ConsumerEndpointImpl* consumer) {
   PERFETTO_DCHECK_THREAD(thread_checker_);
   TracingSession* tracing_session = GetTracingSession(tsid);
@@ -1383,9 +1384,10 @@
     // This will be hit systematically from the PostDelayedTask when directly
     // writing into the file (in which case consumer == nullptr). Suppress the
     // log in this case as it's just spam.
-    if (consumer)
+    if (consumer) {
       PERFETTO_DLOG("Cannot ReadBuffers(): no tracing session is active");
-    return;  // TODO(primiano): signal failure?
+    }
+    return false;
   }
 
   // When a tracing session is waiting for a trigger it is considered empty. If
@@ -1395,24 +1397,22 @@
   // the consumer know there is no data.
   if (!tracing_session->config.trigger_config().triggers().empty() &&
       tracing_session->received_triggers.empty()) {
-    if (consumer)
-      consumer->consumer_->OnTraceData({}, /* has_more = */ false);
     PERFETTO_DLOG(
         "ReadBuffers(): tracing session has not received a trigger yet.");
-    return;
+    return false;
   }
 
   // This can happen if the file is closed by a previous task because it reaches
   // |max_file_size_bytes|.
   if (!tracing_session->write_into_file && !consumer)
-    return;
+    return false;
 
   if (tracing_session->write_into_file && consumer) {
     // If the consumer enabled tracing and asked to save the contents into the
     // passed file makes little sense to also try to read the buffers over IPC,
     // as that would just steal data from the periodic draining task.
     PERFETTO_DFATAL("Consumer trying to read from write_into_file session.");
-    return;
+    return false;
   }
 
   std::vector<TracePacket> packets;
@@ -1601,7 +1601,7 @@
       tracing_session->write_period_ms = 0;
       if (tracing_session->state == TracingSession::STARTED)
         DisableTracing(tsid);
-      return;
+      return true;
     }
 
     auto weak_this = weak_ptr_factory_.GetWeakPtr();
@@ -1611,7 +1611,7 @@
             weak_this->ReadBuffers(tsid, nullptr);
         },
         tracing_session->delay_to_next_write_period_ms());
-    return;
+    return true;
   }  // if (tracing_session->write_into_file)
 
   const bool has_more = did_hit_threshold;
@@ -1627,6 +1627,7 @@
 
   // Keep this as tail call, just in case the consumer re-enters.
   consumer->consumer_->OnTraceData(std::move(packets), has_more);
+  return true;
 }
 
 void TracingServiceImpl::FreeBuffers(TracingSessionID tsid) {
@@ -2340,9 +2341,12 @@
   PERFETTO_DCHECK_THREAD(thread_checker_);
   if (!tracing_session_id_) {
     PERFETTO_LOG("Consumer called ReadBuffers() but tracing was not active");
+    consumer_->OnTraceData({}, /* has_more = */ false);
     return;
   }
-  service_->ReadBuffers(tracing_session_id_, this);
+  if (!service_->ReadBuffers(tracing_session_id_, this)) {
+    consumer_->OnTraceData({}, /* has_more = */ false);
+  }
 }
 
 void TracingServiceImpl::ConsumerEndpointImpl::FreeBuffers() {
@@ -2483,6 +2487,36 @@
   return observable_events_.get();
 }
 
+void TracingServiceImpl::ConsumerEndpointImpl::QueryServiceState(
+    QueryServiceStateCallback callback) {
+  PERFETTO_DCHECK_THREAD(thread_checker_);
+  TracingServiceState svc_state;
+
+  const auto& sessions = service_->tracing_sessions_;
+  svc_state.set_num_sessions(static_cast<int>(sessions.size()));
+
+  int num_started = 0;
+  for (const auto& kv : sessions)
+    num_started += kv.second.state == TracingSession::State::STARTED ? 1 : 0;
+  svc_state.set_num_sessions_started(static_cast<int>(num_started));
+
+  for (const auto& kv : service_->producers_) {
+    auto* producer = svc_state.add_producers();
+    producer->set_id(static_cast<int>(kv.first));
+    producer->set_name(kv.second->name_);
+    producer->set_uid(static_cast<int32_t>(producer->uid()));
+  }
+
+  for (const auto& kv : service_->data_sources_) {
+    const auto& registered_data_source = kv.second;
+    auto* data_source = svc_state.add_data_sources();
+    *data_source->mutable_descriptor() = registered_data_source.descriptor;
+    data_source->set_producer_id(
+        static_cast<int>(registered_data_source.producer_id));
+  }
+  callback(/*success=*/true, svc_state);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // TracingServiceImpl::ProducerEndpointImpl implementation
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index 10ca797..038958e 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -116,6 +116,8 @@
       return base::nullopt;
     }
 
+    uid_t uid() const { return uid_; }
+
    private:
     friend class TracingServiceImpl;
     friend class TracingServiceImplTest;
@@ -182,6 +184,7 @@
     void Attach(const std::string& key) override;
     void GetTraceStats() override;
     void ObserveEvents(uint32_t enabled_event_types) override;
+    void QueryServiceState(QueryServiceStateCallback) override;
 
     // If |observe_data_source_instances == true|, will queue a task to notify
     // the consumer about the state change.
@@ -254,7 +257,7 @@
              uint32_t timeout_ms,
              ConsumerEndpoint::FlushCallback);
   void FlushAndDisableTracing(TracingSessionID);
-  void ReadBuffers(TracingSessionID, ConsumerEndpointImpl*);
+  bool ReadBuffers(TracingSessionID, ConsumerEndpointImpl*);
   void FreeBuffers(TracingSessionID);
 
   // Service implementation.
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index 74eeacf..ae54834 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -211,6 +211,8 @@
 
   consumer_a->DisableTracing();
   consumer_a->WaitForTracingDisabled();
+
+  EXPECT_THAT(consumer_b->ReadBuffers(), ::testing::IsEmpty());
 }
 
 TEST_F(TracingServiceImplTest, RegisterAndUnregister) {
@@ -2758,4 +2760,55 @@
   consumer->WaitForTracingDisabled();
 }
 
+TEST_F(TracingServiceImplTest, QueryServiceState) {
+  std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+  consumer->Connect(svc.get());
+
+  std::unique_ptr<MockProducer> producer1 = CreateMockProducer();
+  producer1->Connect(svc.get(), "producer1");
+
+  std::unique_ptr<MockProducer> producer2 = CreateMockProducer();
+  producer2->Connect(svc.get(), "producer2");
+
+  producer1->RegisterDataSource("common_ds");
+  producer2->RegisterDataSource("common_ds");
+
+  producer1->RegisterDataSource("p1_ds");
+  producer2->RegisterDataSource("p2_ds");
+
+  TracingServiceState svc_state = consumer->QueryServiceState();
+
+  EXPECT_EQ(svc_state.producers_size(), 2u);
+  EXPECT_EQ(svc_state.producers().at(0).id(), 1);
+  EXPECT_EQ(svc_state.producers().at(0).name(), "producer1");
+  EXPECT_EQ(svc_state.producers().at(1).id(), 2);
+  EXPECT_EQ(svc_state.producers().at(1).name(), "producer2");
+
+  EXPECT_EQ(svc_state.data_sources_size(), 4u);
+
+  EXPECT_EQ(svc_state.data_sources().at(0).producer_id(), 1);
+  EXPECT_EQ(svc_state.data_sources().at(0).descriptor().name(), "common_ds");
+
+  EXPECT_EQ(svc_state.data_sources().at(1).producer_id(), 2);
+  EXPECT_EQ(svc_state.data_sources().at(1).descriptor().name(), "common_ds");
+
+  EXPECT_EQ(svc_state.data_sources().at(2).producer_id(), 1);
+  EXPECT_EQ(svc_state.data_sources().at(2).descriptor().name(), "p1_ds");
+
+  EXPECT_EQ(svc_state.data_sources().at(3).producer_id(), 2);
+  EXPECT_EQ(svc_state.data_sources().at(3).descriptor().name(), "p2_ds");
+
+  // Test that descriptors are cleared when a producer disconnects.
+  producer1.reset();
+  svc_state = consumer->QueryServiceState();
+
+  EXPECT_EQ(svc_state.producers_size(), 1u);
+  EXPECT_EQ(svc_state.data_sources_size(), 2u);
+
+  EXPECT_EQ(svc_state.data_sources().at(0).producer_id(), 2);
+  EXPECT_EQ(svc_state.data_sources().at(0).descriptor().name(), "common_ds");
+  EXPECT_EQ(svc_state.data_sources().at(1).producer_id(), 2);
+  EXPECT_EQ(svc_state.data_sources().at(1).descriptor().name(), "p2_ds");
+}
+
 }  // namespace perfetto
diff --git a/src/tracing/core/tracing_service_state.cc b/src/tracing/core/tracing_service_state.cc
new file mode 100644
index 0000000..38601f2
--- /dev/null
+++ b/src/tracing/core/tracing_service_state.cc
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+/*******************************************************************************
+ * AUTOGENERATED - DO NOT EDIT
+ *******************************************************************************
+ * This file has been generated from the protobuf message
+ * perfetto/common/tracing_service_state.proto
+ * by
+ * ../../tools/proto_to_cpp/proto_to_cpp.cc.
+ * If you need to make changes here, change the .proto file and then run
+ * ./tools/gen_tracing_cpp_headers_from_protos
+ */
+
+#include "perfetto/tracing/core/tracing_service_state.h"
+
+#include "perfetto/common/data_source_descriptor.pb.h"
+#include "perfetto/common/tracing_service_state.pb.h"
+
+namespace perfetto {
+
+TracingServiceState::TracingServiceState() = default;
+TracingServiceState::~TracingServiceState() = default;
+TracingServiceState::TracingServiceState(const TracingServiceState&) = default;
+TracingServiceState& TracingServiceState::operator=(
+    const TracingServiceState&) = default;
+TracingServiceState::TracingServiceState(TracingServiceState&&) noexcept =
+    default;
+TracingServiceState& TracingServiceState::operator=(TracingServiceState&&) =
+    default;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TracingServiceState::operator==(const TracingServiceState& other) const {
+  return (producers_ == other.producers_) &&
+         (data_sources_ == other.data_sources_) &&
+         (num_sessions_ == other.num_sessions_) &&
+         (num_sessions_started_ == other.num_sessions_started_);
+}
+#pragma GCC diagnostic pop
+
+void TracingServiceState::FromProto(
+    const perfetto::protos::TracingServiceState& proto) {
+  producers_.clear();
+  for (const auto& field : proto.producers()) {
+    producers_.emplace_back();
+    producers_.back().FromProto(field);
+  }
+
+  data_sources_.clear();
+  for (const auto& field : proto.data_sources()) {
+    data_sources_.emplace_back();
+    data_sources_.back().FromProto(field);
+  }
+
+  static_assert(sizeof(num_sessions_) == sizeof(proto.num_sessions()),
+                "size mismatch");
+  num_sessions_ = static_cast<decltype(num_sessions_)>(proto.num_sessions());
+
+  static_assert(
+      sizeof(num_sessions_started_) == sizeof(proto.num_sessions_started()),
+      "size mismatch");
+  num_sessions_started_ = static_cast<decltype(num_sessions_started_)>(
+      proto.num_sessions_started());
+  unknown_fields_ = proto.unknown_fields();
+}
+
+void TracingServiceState::ToProto(
+    perfetto::protos::TracingServiceState* proto) const {
+  proto->Clear();
+
+  for (const auto& it : producers_) {
+    auto* entry = proto->add_producers();
+    it.ToProto(entry);
+  }
+
+  for (const auto& it : data_sources_) {
+    auto* entry = proto->add_data_sources();
+    it.ToProto(entry);
+  }
+
+  static_assert(sizeof(num_sessions_) == sizeof(proto->num_sessions()),
+                "size mismatch");
+  proto->set_num_sessions(
+      static_cast<decltype(proto->num_sessions())>(num_sessions_));
+
+  static_assert(
+      sizeof(num_sessions_started_) == sizeof(proto->num_sessions_started()),
+      "size mismatch");
+  proto->set_num_sessions_started(
+      static_cast<decltype(proto->num_sessions_started())>(
+          num_sessions_started_));
+  *(proto->mutable_unknown_fields()) = unknown_fields_;
+}
+
+TracingServiceState::Producer::Producer() = default;
+TracingServiceState::Producer::~Producer() = default;
+TracingServiceState::Producer::Producer(const TracingServiceState::Producer&) =
+    default;
+TracingServiceState::Producer& TracingServiceState::Producer::operator=(
+    const TracingServiceState::Producer&) = default;
+TracingServiceState::Producer::Producer(
+    TracingServiceState::Producer&&) noexcept = default;
+TracingServiceState::Producer& TracingServiceState::Producer::operator=(
+    TracingServiceState::Producer&&) = default;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TracingServiceState::Producer::operator==(
+    const TracingServiceState::Producer& other) const {
+  return (id_ == other.id_) && (name_ == other.name_) && (uid_ == other.uid_);
+}
+#pragma GCC diagnostic pop
+
+void TracingServiceState::Producer::FromProto(
+    const perfetto::protos::TracingServiceState_Producer& proto) {
+  static_assert(sizeof(id_) == sizeof(proto.id()), "size mismatch");
+  id_ = static_cast<decltype(id_)>(proto.id());
+
+  static_assert(sizeof(name_) == sizeof(proto.name()), "size mismatch");
+  name_ = static_cast<decltype(name_)>(proto.name());
+
+  static_assert(sizeof(uid_) == sizeof(proto.uid()), "size mismatch");
+  uid_ = static_cast<decltype(uid_)>(proto.uid());
+  unknown_fields_ = proto.unknown_fields();
+}
+
+void TracingServiceState::Producer::ToProto(
+    perfetto::protos::TracingServiceState_Producer* proto) const {
+  proto->Clear();
+
+  static_assert(sizeof(id_) == sizeof(proto->id()), "size mismatch");
+  proto->set_id(static_cast<decltype(proto->id())>(id_));
+
+  static_assert(sizeof(name_) == sizeof(proto->name()), "size mismatch");
+  proto->set_name(static_cast<decltype(proto->name())>(name_));
+
+  static_assert(sizeof(uid_) == sizeof(proto->uid()), "size mismatch");
+  proto->set_uid(static_cast<decltype(proto->uid())>(uid_));
+  *(proto->mutable_unknown_fields()) = unknown_fields_;
+}
+
+TracingServiceState::DataSource::DataSource() = default;
+TracingServiceState::DataSource::~DataSource() = default;
+TracingServiceState::DataSource::DataSource(
+    const TracingServiceState::DataSource&) = default;
+TracingServiceState::DataSource& TracingServiceState::DataSource::operator=(
+    const TracingServiceState::DataSource&) = default;
+TracingServiceState::DataSource::DataSource(
+    TracingServiceState::DataSource&&) noexcept = default;
+TracingServiceState::DataSource& TracingServiceState::DataSource::operator=(
+    TracingServiceState::DataSource&&) = default;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+bool TracingServiceState::DataSource::operator==(
+    const TracingServiceState::DataSource& other) const {
+  return (descriptor_ == other.descriptor_) &&
+         (producer_id_ == other.producer_id_);
+}
+#pragma GCC diagnostic pop
+
+void TracingServiceState::DataSource::FromProto(
+    const perfetto::protos::TracingServiceState_DataSource& proto) {
+  descriptor_.FromProto(proto.descriptor());
+
+  static_assert(sizeof(producer_id_) == sizeof(proto.producer_id()),
+                "size mismatch");
+  producer_id_ = static_cast<decltype(producer_id_)>(proto.producer_id());
+  unknown_fields_ = proto.unknown_fields();
+}
+
+void TracingServiceState::DataSource::ToProto(
+    perfetto::protos::TracingServiceState_DataSource* proto) const {
+  proto->Clear();
+
+  descriptor_.ToProto(proto->mutable_descriptor());
+
+  static_assert(sizeof(producer_id_) == sizeof(proto->producer_id()),
+                "size mismatch");
+  proto->set_producer_id(
+      static_cast<decltype(proto->producer_id())>(producer_id_));
+  *(proto->mutable_unknown_fields()) = unknown_fields_;
+}
+
+}  // namespace perfetto
diff --git a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
index 26f4917..69465cf 100644
--- a/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
+++ b/src/tracing/ipc/consumer/consumer_ipc_client_impl.cc
@@ -25,6 +25,7 @@
 #include "perfetto/tracing/core/observable_events.h"
 #include "perfetto/tracing/core/trace_config.h"
 #include "perfetto/tracing/core/trace_stats.h"
+#include "perfetto/tracing/core/tracing_service_state.h"
 
 // TODO(fmayer): Add a test to check to what happens when ConsumerIPCClientImpl
 // gets destroyed w.r.t. the Consumer pointer. Also think to lifetime of the
@@ -328,4 +329,25 @@
   consumer_port_.ObserveEvents(req, std::move(async_response));
 }
 
+void ConsumerIPCClientImpl::QueryServiceState(
+    QueryServiceStateCallback callback) {
+  if (!connected_) {
+    PERFETTO_DLOG(
+        "Cannot QueryServiceState(), not connected to tracing service");
+    return;
+  }
+
+  protos::QueryServiceStateRequest req;
+  ipc::Deferred<protos::QueryServiceStateResponse> async_response;
+  async_response.Bind(
+      [callback](ipc::AsyncResult<protos::QueryServiceStateResponse> response) {
+        if (!response)
+          callback(false, TracingServiceState());
+        TracingServiceState svc_state;
+        svc_state.FromProto(response->service_state());
+        callback(true, svc_state);
+      });
+  consumer_port_.QueryServiceState(req, std::move(async_response));
+}
+
 }  // namespace perfetto
diff --git a/src/tracing/ipc/consumer/consumer_ipc_client_impl.h b/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
index e930cee..c3933c0 100644
--- a/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
+++ b/src/tracing/ipc/consumer/consumer_ipc_client_impl.h
@@ -70,6 +70,7 @@
   void Attach(const std::string& key) override;
   void GetTraceStats() override;
   void ObserveEvents(uint32_t enabled_event_types) override;
+  void QueryServiceState(QueryServiceStateCallback) override;
 
   // ipc::ServiceProxy::EventListener implementation.
   // These methods are invoked by the IPC layer, which knows nothing about
diff --git a/src/tracing/ipc/service/consumer_ipc_service.cc b/src/tracing/ipc/service/consumer_ipc_service.cc
index 4e5afc9..8a31f1f 100644
--- a/src/tracing/ipc/service/consumer_ipc_service.cc
+++ b/src/tracing/ipc/service/consumer_ipc_service.cc
@@ -29,6 +29,7 @@
 #include "perfetto/tracing/core/trace_packet.h"
 #include "perfetto/tracing/core/trace_stats.h"
 #include "perfetto/tracing/core/tracing_service.h"
+#include "perfetto/tracing/core/tracing_service_state.h"
 
 namespace perfetto {
 
@@ -187,6 +188,22 @@
     remote_consumer->CloseObserveEventsResponseStream();
 }
 
+// Called by the IPC layer.
+void ConsumerIPCService::QueryServiceState(
+    const protos::QueryServiceStateRequest&,
+    DeferredQueryServiceStateResponse resp) {
+  RemoteConsumer* remote_consumer = GetConsumerForCurrentRequest();
+  auto it = pending_query_service_responses_.insert(
+      pending_query_service_responses_.end(), std::move(resp));
+  auto weak_this = weak_ptr_factory_.GetWeakPtr();
+  auto callback = [weak_this, it](bool success,
+                                  const TracingServiceState& svc_state) {
+    if (weak_this)
+      weak_this->OnQueryServiceCallback(success, svc_state, std::move(it));
+  };
+  remote_consumer->service_endpoint->QueryServiceState(callback);
+}
+
 // Called by the service in response to a service_endpoint->Flush() request.
 void ConsumerIPCService::OnFlushCallback(
     bool success,
@@ -200,6 +217,22 @@
   }
 }
 
+// Called by the service in response to service_endpoint->QueryServiceState().
+void ConsumerIPCService::OnQueryServiceCallback(
+    bool success,
+    const TracingServiceState& svc_state,
+    PendingQuerySvcResponses::iterator pending_response_it) {
+  DeferredQueryServiceStateResponse response(std::move(*pending_response_it));
+  pending_query_service_responses_.erase(pending_response_it);
+  if (success) {
+    auto resp = ipc::AsyncResult<protos::QueryServiceStateResponse>::Create();
+    svc_state.ToProto(resp->mutable_service_state());
+    response.Resolve(std::move(resp));
+  } else {
+    response.Reject();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // RemoteConsumer methods
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tracing/ipc/service/consumer_ipc_service.h b/src/tracing/ipc/service/consumer_ipc_service.h
index 2752fb3..cb9aa0f 100644
--- a/src/tracing/ipc/service/consumer_ipc_service.h
+++ b/src/tracing/ipc/service/consumer_ipc_service.h
@@ -31,6 +31,8 @@
 
 namespace perfetto {
 
+class TracingServiceState;
+
 namespace ipc {
 class Host;
 }  // namespace ipc
@@ -63,6 +65,8 @@
                      DeferredGetTraceStatsResponse) override;
   void ObserveEvents(const protos::ObserveEventsRequest&,
                      DeferredObserveEventsResponse) override;
+  void QueryServiceState(const protos::QueryServiceStateRequest&,
+                         DeferredQueryServiceStateResponse) override;
   void OnClientDisconnected() override;
 
  private:
@@ -117,6 +121,7 @@
 
   // This has to be a container that doesn't invalidate iterators.
   using PendingFlushResponses = std::list<DeferredFlushResponse>;
+  using PendingQuerySvcResponses = std::list<DeferredQueryServiceStateResponse>;
 
   ConsumerIPCService(const ConsumerIPCService&) = delete;
   ConsumerIPCService& operator=(const ConsumerIPCService&) = delete;
@@ -126,6 +131,9 @@
   RemoteConsumer* GetConsumerForCurrentRequest();
 
   void OnFlushCallback(bool success, PendingFlushResponses::iterator);
+  void OnQueryServiceCallback(bool success,
+                              const TracingServiceState&,
+                              PendingQuerySvcResponses::iterator);
 
   TracingService* const core_service_;
 
@@ -134,6 +142,7 @@
   std::map<ipc::ClientID, std::unique_ptr<RemoteConsumer>> consumers_;
 
   PendingFlushResponses pending_flush_responses_;
+  PendingQuerySvcResponses pending_query_service_responses_;
 
   base::WeakPtrFactory<ConsumerIPCService> weak_ptr_factory_;  // Keep last.
 };
diff --git a/src/tracing/test/mock_consumer.cc b/src/tracing/test/mock_consumer.cc
index 15c1400..c2f4548 100644
--- a/src/tracing/test/mock_consumer.cc
+++ b/src/tracing/test/mock_consumer.cc
@@ -161,4 +161,20 @@
   return events;
 }
 
+TracingServiceState MockConsumer::QueryServiceState() {
+  static int i = 0;
+  TracingServiceState res;
+  std::string checkpoint_name = "query_service_state_" + std::to_string(i++);
+  auto checkpoint = task_runner_->CreateCheckpoint(checkpoint_name);
+  auto callback = [checkpoint, &res](bool success,
+                                     const TracingServiceState& svc_state) {
+    EXPECT_TRUE(success);
+    res = svc_state;
+    checkpoint();
+  };
+  service_endpoint_->QueryServiceState(callback);
+  task_runner_->RunUntilCheckpoint(checkpoint_name);
+  return res;
+}
+
 }  // namespace perfetto
diff --git a/src/tracing/test/mock_consumer.h b/src/tracing/test/mock_consumer.h
index a297042..fe43fb5 100644
--- a/src/tracing/test/mock_consumer.h
+++ b/src/tracing/test/mock_consumer.h
@@ -23,6 +23,7 @@
 #include "perfetto/tracing/core/consumer.h"
 #include "perfetto/tracing/core/trace_packet.h"
 #include "perfetto/tracing/core/tracing_service.h"
+#include "perfetto/tracing/core/tracing_service_state.h"
 
 #include "perfetto/trace/trace_packet.pb.h"
 
@@ -57,6 +58,7 @@
   std::vector<protos::TracePacket> ReadBuffers();
   void GetTraceStats();
   void WaitForTraceStats(bool success);
+  TracingServiceState QueryServiceState();
   void ObserveEvents(uint32_t enabled_event_types);
   ObservableEvents WaitForObservableEvents();
 
diff --git a/test/end_to_end_integrationtest.cc b/test/end_to_end_integrationtest.cc
index 2cc9a21..15bef9d 100644
--- a/test/end_to_end_integrationtest.cc
+++ b/test/end_to_end_integrationtest.cc
@@ -601,10 +601,10 @@
 
   EXPECT_EQ(1,
             ExecPerfetto({"-c", "-", "--txt", "-o", "-", "--attach=foo"}, cfg));
-  EXPECT_THAT(stderr_, HasSubstr("trace config with --attach"));
+  EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config"));
 
   EXPECT_EQ(1, ExecPerfetto({"-t", "2s", "-o", "-", "--attach=foo"}, cfg));
-  EXPECT_THAT(stderr_, HasSubstr("trace config with --attach"));
+  EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config"));
 
   EXPECT_EQ(1, ExecPerfetto({"--attach"}, cfg));
   EXPECT_THAT(stderr_, ContainsRegex("option.*--attach.*requires an argument"));
@@ -614,6 +614,12 @@
 
   EXPECT_EQ(1, ExecPerfetto({"-t", "2s", "--detach=foo"}, cfg));
   EXPECT_THAT(stderr_, HasSubstr("--out or --dropbox is required"));
+
+  EXPECT_EQ(1, ExecPerfetto({"-t", "2s", "--query"}, cfg));
+  EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config"));
+
+  EXPECT_EQ(1, ExecPerfetto({"-c", "-", "--query"}, cfg));
+  EXPECT_THAT(stderr_, HasSubstr("Cannot specify a trace config"));
 }
 
 TEST_F(PerfettoCmdlineTest, NoSanitizers(TxtConfig)) {
@@ -998,4 +1004,9 @@
   EXPECT_FALSE(base::ReadFile(path, &trace_str));
 }
 
+TEST_F(PerfettoCmdlineTest, NoSanitizers(Query)) {
+  EXPECT_EQ(0, ExecPerfetto({"--query"})) << stderr_;
+  EXPECT_EQ(0, ExecPerfetto({"--query-raw"})) << stderr_;
+}
+
 }  // namespace perfetto
diff --git a/tools/gen_all b/tools/gen_all
index 27dc5f7..6b8e062 100755
--- a/tools/gen_all
+++ b/tools/gen_all
@@ -29,8 +29,9 @@
 def call(cmd, *args):
   path = os.path.join('tools', cmd)
   command = [path] + list(args)
+  print 'Running ', ' '.join(command)
   try:
-    subprocess.check_call([path] + list(args), cwd=ROOT_DIR)
+    subprocess.check_call(command, cwd=ROOT_DIR)
   except subprocess.CalledProcessError as e:
     assert False, 'Command: {} failed'.format(' '.join(command))
 
@@ -50,6 +51,7 @@
     call('gen_merged_protos')
     call('gen_binary_descriptors', '--protoc', protoc_path(out))
     call('gen_tracing_cpp_headers_from_protos', out)
+    call('gen_amalgamated', '--check', '--quiet')  # Keep last
 
   except AssertionError as e:
     if not str(e):
diff --git a/tools/gen_tracing_cpp_headers_from_protos b/tools/gen_tracing_cpp_headers_from_protos
index 01df694..d70bb3c 100755
--- a/tools/gen_tracing_cpp_headers_from_protos
+++ b/tools/gen_tracing_cpp_headers_from_protos
@@ -20,13 +20,14 @@
 PROTOS = (
   'perfetto/common/android_log_constants.proto',
   'perfetto/common/commit_data_request.proto',
+  'perfetto/common/data_source_descriptor.proto',
   'perfetto/common/observable_events.proto',
   'perfetto/common/sys_stats_counters.proto',
   'perfetto/common/trace_stats.proto',
+  'perfetto/common/tracing_service_state.proto',
   'perfetto/config/android/android_log_config.proto',
   'perfetto/config/chrome/chrome_config.proto',
   'perfetto/config/data_source_config.proto',
-  'perfetto/config/data_source_descriptor.proto',
   'perfetto/config/ftrace/ftrace_config.proto',
   'perfetto/config/inode_file/inode_file_config.proto',
   'perfetto/config/power/android_power_config.proto',