Create linux.system_info probe reporting CpuInfo

The new probe reports only basic CPU information:
- "processor" value from /proc/cpuinfo
- frequencies from
/sys/devices/system/cpu/cpuX/cpufreq/scaling_available_frequencies

It is the first building block of the coarse CPU data source.

Bug: 153092449
Test: perfetto_unittests
Change-Id: I0158f6c2918531a5da2438cfc541644f1869e612
diff --git a/Android.bp b/Android.bp
index e1931e2..45bfe90 100644
--- a/Android.bp
+++ b/Android.bp
@@ -109,6 +109,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_base_unix_socket",
@@ -178,6 +179,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
   defaults: [
@@ -306,6 +308,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_android_internal_headers",
     ":perfetto_src_android_internal_lazy_library_loader",
@@ -328,6 +331,7 @@
     ":perfetto_src_traced_probes_probes_src",
     ":perfetto_src_traced_probes_ps_ps",
     ":perfetto_src_traced_probes_sys_stats_sys_stats",
+    ":perfetto_src_traced_probes_system_info_system_info",
     ":perfetto_src_traced_service_service",
     ":perfetto_src_tracing_common",
     ":perfetto_src_tracing_consumer_api_deprecated_consumer_api_deprecated",
@@ -385,6 +389,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
   defaults: [
@@ -487,6 +492,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_base_unix_socket",
@@ -549,6 +555,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
   export_generated_headers: [
@@ -590,6 +597,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
   defaults: [
@@ -653,6 +661,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_android_internal_headers",
     ":perfetto_src_android_internal_lazy_library_loader",
@@ -715,6 +724,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
   ],
@@ -794,6 +804,8 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_cpp_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_cpp_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_android_internal_headers",
@@ -817,6 +829,7 @@
     ":perfetto_src_traced_probes_probes_src",
     ":perfetto_src_traced_probes_ps_ps",
     ":perfetto_src_traced_probes_sys_stats_sys_stats",
+    ":perfetto_src_traced_probes_system_info_system_info",
     ":perfetto_src_tracing_common",
     ":perfetto_src_tracing_core_core",
     ":perfetto_src_tracing_core_service",
@@ -897,6 +910,8 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_cpp_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
@@ -952,6 +967,8 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_cpp_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
@@ -1030,6 +1047,8 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_cpp_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_cpp_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_android_internal_headers",
@@ -1053,6 +1072,7 @@
     ":perfetto_src_traced_probes_probes_src",
     ":perfetto_src_traced_probes_ps_ps",
     ":perfetto_src_traced_probes_sys_stats_sys_stats",
+    ":perfetto_src_traced_probes_system_info_system_info",
     ":perfetto_src_tracing_common",
     ":perfetto_src_tracing_core_core",
     ":perfetto_src_tracing_core_service",
@@ -1118,6 +1138,8 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_cpp_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
@@ -1173,6 +1195,8 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_cpp_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
@@ -1396,6 +1420,8 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_cpp_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_cpp_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_android_internal_headers",
@@ -1432,6 +1458,7 @@
     ":perfetto_src_traced_probes_probes_src",
     ":perfetto_src_traced_probes_ps_ps",
     ":perfetto_src_traced_probes_sys_stats_sys_stats",
+    ":perfetto_src_traced_probes_system_info_system_info",
     ":perfetto_src_tracing_client_api_without_backends",
     ":perfetto_src_tracing_common",
     ":perfetto_src_tracing_core_core",
@@ -1514,6 +1541,8 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_cpp_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
@@ -5158,6 +5187,112 @@
   ],
 }
 
+// GN: //protos/perfetto/trace/system_info:cpp
+genrule {
+  name: "perfetto_protos_perfetto_trace_system_info_cpp_gen",
+  srcs: [
+    "protos/perfetto/trace/system_info/cpu_info.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=wrapper_namespace=gen:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/trace/system_info/cpu_info.gen.cc",
+  ],
+}
+
+// GN: //protos/perfetto/trace/system_info:cpp
+genrule {
+  name: "perfetto_protos_perfetto_trace_system_info_cpp_gen_headers",
+  srcs: [
+    "protos/perfetto/trace/system_info/cpu_info.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "perfetto_src_protozero_protoc_plugin_cppgen_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_cppgen_plugin) --plugin_out=wrapper_namespace=gen:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/trace/system_info/cpu_info.gen.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
+// GN: //protos/perfetto/trace/system_info:lite
+genrule {
+  name: "perfetto_protos_perfetto_trace_system_info_lite_gen",
+  srcs: [
+    "protos/perfetto/trace/system_info/cpu_info.proto",
+  ],
+  tools: [
+    "aprotoc",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/trace/system_info/cpu_info.pb.cc",
+  ],
+}
+
+// GN: //protos/perfetto/trace/system_info:lite
+genrule {
+  name: "perfetto_protos_perfetto_trace_system_info_lite_gen_headers",
+  srcs: [
+    "protos/perfetto/trace/system_info/cpu_info.proto",
+  ],
+  tools: [
+    "aprotoc",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --cpp_out=lite=true:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/trace/system_info/cpu_info.pb.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
+// GN: //protos/perfetto/trace/system_info:zero
+genrule {
+  name: "perfetto_protos_perfetto_trace_system_info_zero_gen",
+  srcs: [
+    "protos/perfetto/trace/system_info/cpu_info.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "protozero_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/trace/system_info/cpu_info.pbzero.cc",
+  ],
+}
+
+// GN: //protos/perfetto/trace/system_info:zero
+genrule {
+  name: "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
+  srcs: [
+    "protos/perfetto/trace/system_info/cpu_info.proto",
+  ],
+  tools: [
+    "aprotoc",
+    "protozero_plugin",
+  ],
+  cmd: "mkdir -p $(genDir)/external/perfetto/ && $(location aprotoc) --proto_path=external/perfetto --plugin=protoc-gen-plugin=$(location protozero_plugin) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/ $(in)",
+  out: [
+    "external/perfetto/protos/perfetto/trace/system_info/cpu_info.pbzero.h",
+  ],
+  export_include_dirs: [
+    ".",
+    "protos",
+  ],
+}
+
 // GN: //protos/perfetto/trace/track_event:cpp
 genrule {
   name: "perfetto_protos_perfetto_trace_track_event_cpp_gen",
@@ -6792,6 +6927,22 @@
   ],
 }
 
+// GN: //src/traced/probes/system_info:system_info
+filegroup {
+  name: "perfetto_src_traced_probes_system_info_system_info",
+  srcs: [
+    "src/traced/probes/system_info/system_info_data_source.cc",
+  ],
+}
+
+// GN: //src/traced/probes/system_info:unittests
+filegroup {
+  name: "perfetto_src_traced_probes_system_info_unittests",
+  srcs: [
+    "src/traced/probes/system_info/system_info_data_source_unittest.cc",
+  ],
+}
+
 // GN: //src/traced/probes:unittests
 filegroup {
   name: "perfetto_src_traced_probes_unittests",
@@ -7098,6 +7249,7 @@
     ":perfetto_protos_perfetto_trace_profiling_lite_gen",
     ":perfetto_protos_perfetto_trace_ps_lite_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_lite_gen",
+    ":perfetto_protos_perfetto_trace_system_info_lite_gen",
     ":perfetto_protos_perfetto_trace_track_event_lite_gen",
   ],
   shared_libs: [
@@ -7133,6 +7285,7 @@
     "perfetto_protos_perfetto_trace_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_trace_ps_lite_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_lite_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_lite_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_lite_gen_headers",
   ],
   export_generated_headers: [
@@ -7160,6 +7313,7 @@
     "perfetto_protos_perfetto_trace_profiling_lite_gen_headers",
     "perfetto_protos_perfetto_trace_ps_lite_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_lite_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_lite_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_lite_gen_headers",
   ],
   defaults: [
@@ -7246,6 +7400,8 @@
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_cpp_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_cpp_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_cpp_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_android_internal_headers",
@@ -7334,6 +7490,8 @@
     ":perfetto_src_traced_probes_ps_unittests",
     ":perfetto_src_traced_probes_sys_stats_sys_stats",
     ":perfetto_src_traced_probes_sys_stats_unittests",
+    ":perfetto_src_traced_probes_system_info_system_info",
+    ":perfetto_src_traced_probes_system_info_unittests",
     ":perfetto_src_traced_probes_unittests",
     ":perfetto_src_traced_service_service",
     ":perfetto_src_traced_service_unittests",
@@ -7422,6 +7580,8 @@
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_cpp_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_cpp_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
     "perfetto_src_ipc_test_messages_cpp_gen_headers",
@@ -7526,6 +7686,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_profiling_symbolizer_symbolize_database",
@@ -7581,6 +7742,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
   defaults: [
@@ -7635,6 +7797,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_protos_third_party_pprof_zero_gen",
     ":perfetto_src_base_base",
@@ -7696,6 +7859,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
     "perfetto_protos_third_party_pprof_zero_gen_headers",
   ],
@@ -7780,6 +7944,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_base_unix_socket",
@@ -7852,6 +8017,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
   ],
   defaults: [
@@ -7939,6 +8105,7 @@
     ":perfetto_protos_perfetto_trace_profiling_zero_gen",
     ":perfetto_protos_perfetto_trace_ps_zero_gen",
     ":perfetto_protos_perfetto_trace_sys_stats_zero_gen",
+    ":perfetto_protos_perfetto_trace_system_info_zero_gen",
     ":perfetto_protos_perfetto_trace_track_event_zero_gen",
     ":perfetto_src_base_base",
     ":perfetto_src_base_unix_socket",
@@ -7996,6 +8163,7 @@
     "perfetto_protos_perfetto_trace_profiling_zero_gen_headers",
     "perfetto_protos_perfetto_trace_ps_zero_gen_headers",
     "perfetto_protos_perfetto_trace_sys_stats_zero_gen_headers",
+    "perfetto_protos_perfetto_trace_system_info_zero_gen_headers",
     "perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
     "perfetto_src_perfetto_cmd_protos_gen_headers",
   ],
diff --git a/BUILD b/BUILD
index 042d95a..235efe7 100644
--- a/BUILD
+++ b/BUILD
@@ -153,6 +153,7 @@
         ":protos_perfetto_trace_profiling_zero",
         ":protos_perfetto_trace_ps_zero",
         ":protos_perfetto_trace_sys_stats_zero",
+        ":protos_perfetto_trace_system_info_zero",
         ":protos_perfetto_trace_track_event_zero",
     ],
 )
@@ -182,6 +183,7 @@
         ":src_traced_probes_probes_src",
         ":src_traced_probes_ps_ps",
         ":src_traced_probes_sys_stats_sys_stats",
+        ":src_traced_probes_system_info_system_info",
         ":src_traced_service_service",
         ":src_tracing_common",
         ":src_tracing_consumer_api_deprecated_consumer_api_deprecated",
@@ -245,6 +247,7 @@
         ":protos_perfetto_trace_profiling_zero",
         ":protos_perfetto_trace_ps_zero",
         ":protos_perfetto_trace_sys_stats_zero",
+        ":protos_perfetto_trace_system_info_zero",
         ":protos_perfetto_trace_track_event_zero",
     ],
     linkstatic = True,
@@ -1150,6 +1153,15 @@
     ],
 )
 
+# GN target: //src/traced/probes/system_info:system_info
+filegroup(
+    name = "src_traced_probes_system_info_system_info",
+    srcs = [
+        "src/traced/probes/system_info/system_info_data_source.cc",
+        "src/traced/probes/system_info/system_info_data_source.h",
+    ],
+)
+
 # GN target: //src/traced/probes:data_source
 filegroup(
     name = "src_traced_probes_data_source",
@@ -2290,6 +2302,7 @@
         ":protos_perfetto_trace_profiling_protos",
         ":protos_perfetto_trace_ps_protos",
         ":protos_perfetto_trace_sys_stats_protos",
+        ":protos_perfetto_trace_system_info_protos",
         ":protos_perfetto_trace_track_event_protos",
     ],
 )
@@ -2482,6 +2495,33 @@
     ],
 )
 
+# GN target: //protos/perfetto/trace/system_info:lite
+perfetto_cc_proto_library(
+    name = "protos_perfetto_trace_system_info_lite",
+    deps = [
+        ":protos_perfetto_trace_system_info_protos",
+    ],
+)
+
+# GN target: //protos/perfetto/trace/system_info:zero
+perfetto_proto_library(
+    name = "protos_perfetto_trace_system_info_protos",
+    srcs = [
+        "protos/perfetto/trace/system_info/cpu_info.proto",
+    ],
+    visibility = [
+        PERFETTO_CONFIG.proto_library_visibility,
+    ],
+)
+
+# GN target: //protos/perfetto/trace/system_info:zero
+perfetto_cc_protozero_library(
+    name = "protos_perfetto_trace_system_info_zero",
+    deps = [
+        ":protos_perfetto_trace_system_info_protos",
+    ],
+)
+
 # GN target: //protos/perfetto/trace/track_event:lite
 perfetto_cc_proto_library(
     name = "protos_perfetto_trace_track_event_lite",
@@ -2643,6 +2683,7 @@
         ":protos_perfetto_trace_profiling_zero",
         ":protos_perfetto_trace_ps_zero",
         ":protos_perfetto_trace_sys_stats_zero",
+        ":protos_perfetto_trace_system_info_zero",
         ":protos_perfetto_trace_track_event_zero",
     ],
     linkstatic = True,
@@ -2721,6 +2762,7 @@
         ":protos_perfetto_trace_profiling_zero",
         ":protos_perfetto_trace_ps_zero",
         ":protos_perfetto_trace_sys_stats_zero",
+        ":protos_perfetto_trace_system_info_zero",
         ":protos_perfetto_trace_track_event_zero",
         ":src_perfetto_cmd_protos",
     ] + PERFETTO_CONFIG.deps.zlib,
@@ -2787,6 +2829,7 @@
                ":protos_perfetto_trace_profiling_zero",
                ":protos_perfetto_trace_ps_zero",
                ":protos_perfetto_trace_sys_stats_zero",
+               ":protos_perfetto_trace_system_info_zero",
                ":protos_perfetto_trace_track_event_zero",
            ] + PERFETTO_CONFIG.deps.jsoncpp +
            PERFETTO_CONFIG.deps.sqlite +
@@ -2865,6 +2908,7 @@
                ":protos_perfetto_trace_profiling_zero",
                ":protos_perfetto_trace_ps_zero",
                ":protos_perfetto_trace_sys_stats_zero",
+               ":protos_perfetto_trace_system_info_zero",
                ":protos_perfetto_trace_track_event_zero",
            ] + PERFETTO_CONFIG.deps.jsoncpp +
            PERFETTO_CONFIG.deps.linenoise +
@@ -2954,6 +2998,7 @@
         ":protos_perfetto_trace_profiling_zero",
         ":protos_perfetto_trace_ps_zero",
         ":protos_perfetto_trace_sys_stats_zero",
+        ":protos_perfetto_trace_system_info_zero",
         ":protos_perfetto_trace_track_event_zero",
         ":protos_third_party_pprof_zero",
     ] + PERFETTO_CONFIG.deps.zlib,
@@ -3028,6 +3073,7 @@
                ":protos_perfetto_trace_profiling_zero",
                ":protos_perfetto_trace_ps_zero",
                ":protos_perfetto_trace_sys_stats_zero",
+               ":protos_perfetto_trace_system_info_zero",
                ":protos_perfetto_trace_track_event_zero",
                ":protos_third_party_pprof_zero",
            ] + PERFETTO_CONFIG.deps.jsoncpp +
diff --git a/protos/perfetto/trace/BUILD.gn b/protos/perfetto/trace/BUILD.gn
index 9f27411..b644aaf 100644
--- a/protos/perfetto/trace/BUILD.gn
+++ b/protos/perfetto/trace/BUILD.gn
@@ -87,6 +87,7 @@
     "profiling:@TYPE@",
     "ps:@TYPE@",
     "sys_stats:@TYPE@",
+    "system_info:@TYPE@",
     "track_event:@TYPE@",
   ]
   sources = proto_sources_non_minimal
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 077ab24..228c281 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -3647,6 +3647,28 @@
 
 // End of protos/perfetto/trace/system_info.proto
 
+// Begin of protos/perfetto/trace/system_info/cpu_info.proto
+
+// Information about CPUs from procfs and sysfs.
+message CpuInfo {
+  // Information about a single CPU.
+  message Cpu {
+    // Value of "Processor" field from /proc/cpuinfo for this CPU.
+    // Example: "AArch64 Processor rev 12 (aarch64)"
+    optional string processor = 1;
+
+    // Frequencies from
+    // /sys/devices/system/cpu/cpuX/cpufreq/scaling_available_frequencies
+    // where X is the index of this CPU.
+    repeated uint32 frequencies = 2;
+  }
+
+  // Describes available CPUs, one entry per CPU.
+  repeated Cpu cpus = 1;
+}
+
+// End of protos/perfetto/trace/system_info/cpu_info.proto
+
 // Begin of protos/perfetto/trace/trace.proto
 
 message Trace {
@@ -3667,7 +3689,7 @@
 // TracePacket(s).
 //
 // Next reserved id: 13 (up to 15).
-// Next id: 67.
+// Next id: 68.
 message TracePacket {
   // The timestamp of the TracePacket.
   // By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -3719,6 +3741,7 @@
     GpuLog gpu_log = 63;
     VulkanApiEvent vulkan_api_event = 65;
     PerfSample perf_sample = 66;
+    CpuInfo cpu_info = 67;
 
     // Only used in profile packets.
     ProfiledFrameSymbols profiled_frame_symbols = 55;
diff --git a/protos/perfetto/trace/system_info/BUILD.gn b/protos/perfetto/trace/system_info/BUILD.gn
new file mode 100644
index 0000000..f8297ed
--- /dev/null
+++ b/protos/perfetto/trace/system_info/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright (C) 2020 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.
+
+import("../../../../gn/proto_library.gni")
+
+perfetto_proto_library("@TYPE@") {
+  sources = [ "cpu_info.proto" ]
+}
diff --git a/protos/perfetto/trace/system_info/cpu_info.proto b/protos/perfetto/trace/system_info/cpu_info.proto
new file mode 100644
index 0000000..62f17e0
--- /dev/null
+++ b/protos/perfetto/trace/system_info/cpu_info.proto
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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";
+package perfetto.protos;
+
+// Information about CPUs from procfs and sysfs.
+message CpuInfo {
+  // Information about a single CPU.
+  message Cpu {
+    // Value of "Processor" field from /proc/cpuinfo for this CPU.
+    // Example: "AArch64 Processor rev 12 (aarch64)"
+    optional string processor = 1;
+
+    // Frequencies from
+    // /sys/devices/system/cpu/cpuX/cpufreq/scaling_available_frequencies
+    // where X is the index of this CPU.
+    repeated uint32 frequencies = 2;
+  }
+
+  // Describes available CPUs, one entry per CPU.
+  repeated Cpu cpus = 1;
+}
diff --git a/protos/perfetto/trace/trace_packet.proto b/protos/perfetto/trace/trace_packet.proto
index 3b6cf50..ca5f7ce 100644
--- a/protos/perfetto/trace/trace_packet.proto
+++ b/protos/perfetto/trace/trace_packet.proto
@@ -44,6 +44,7 @@
 import "protos/perfetto/trace/ps/process_tree.proto";
 import "protos/perfetto/trace/sys_stats/sys_stats.proto";
 import "protos/perfetto/trace/system_info.proto";
+import "protos/perfetto/trace/system_info/cpu_info.proto";
 import "protos/perfetto/trace/trace_packet_defaults.proto";
 import "protos/perfetto/trace/track_event/process_descriptor.proto";
 import "protos/perfetto/trace/track_event/thread_descriptor.proto";
@@ -58,7 +59,7 @@
 // TracePacket(s).
 //
 // Next reserved id: 13 (up to 15).
-// Next id: 67.
+// Next id: 68.
 message TracePacket {
   // The timestamp of the TracePacket.
   // By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
@@ -110,6 +111,7 @@
     GpuLog gpu_log = 63;
     VulkanApiEvent vulkan_api_event = 65;
     PerfSample perf_sample = 66;
+    CpuInfo cpu_info = 67;
 
     // Only used in profile packets.
     ProfiledFrameSymbols profiled_frame_symbols = 55;
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index 4bdfba5..ee68f28 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -60,6 +60,7 @@
     "power",
     "ps",
     "sys_stats",
+    "system_info",
   ]
   sources = [
     "probes_producer.cc",
@@ -92,5 +93,6 @@
     "packages_list:unittests",
     "ps:unittests",
     "sys_stats:unittests",
+    "system_info:unittests",
   ]
 }
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index f182f5d..787e799 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -42,6 +42,7 @@
 #include "src/traced/probes/probes_data_source.h"
 #include "src/traced/probes/ps/process_stats_data_source.h"
 #include "src/traced/probes/sys_stats/sys_stats_data_source.h"
+#include "src/traced/probes/system_info/system_info_data_source.h"
 
 #include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
 #include "protos/perfetto/trace/filesystem/inode_file_map.pbzero.h"
@@ -70,6 +71,7 @@
     &AndroidLogDataSource::descriptor,    //
     &PackagesListDataSource::descriptor,  //
     &MetatraceDataSource::descriptor,     //
+    &SystemInfoDataSource::descriptor,    //
 };
 }  // namespace
 
@@ -164,6 +166,8 @@
     data_source = CreatePackagesListDataSource(session_id, config);
   } else if (config.name() == MetatraceDataSource::descriptor.name) {
     data_source = CreateMetatraceDataSource(session_id, config);
+  } else if (config.name() == SystemInfoDataSource::descriptor.name) {
+    data_source = CreateSystemInfoDataSource(session_id, config);
   }
 
   if (!data_source) {
@@ -299,6 +303,14 @@
       task_runner_, session_id, endpoint_->CreateTraceWriter(buffer_id)));
 }
 
+std::unique_ptr<ProbesDataSource> ProbesProducer::CreateSystemInfoDataSource(
+    TracingSessionID session_id,
+    const DataSourceConfig& config) {
+  auto buffer_id = static_cast<BufferID>(config.target_buffer());
+  return std::unique_ptr<ProbesDataSource>(new SystemInfoDataSource(
+      session_id, endpoint_->CreateTraceWriter(buffer_id)));
+}
+
 void ProbesProducer::StopDataSource(DataSourceInstanceID id) {
   PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
   auto it = data_sources_.find(id);
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index 1cdbd28..7cab1ab 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -87,6 +87,9 @@
   std::unique_ptr<ProbesDataSource> CreateMetatraceDataSource(
       TracingSessionID session_id,
       const DataSourceConfig& config);
+  std::unique_ptr<ProbesDataSource> CreateSystemInfoDataSource(
+      TracingSessionID session_id,
+      const DataSourceConfig& config);
 
  private:
   enum State {
diff --git a/src/traced/probes/system_info/BUILD.gn b/src/traced/probes/system_info/BUILD.gn
new file mode 100644
index 0000000..c8b3584
--- /dev/null
+++ b/src/traced/probes/system_info/BUILD.gn
@@ -0,0 +1,43 @@
+# Copyright (C) 2020 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.
+
+import("../../../../gn/test.gni")
+
+source_set("system_info") {
+  public_deps = [ "../../../tracing/core" ]
+  deps = [
+    "..:data_source",
+    "../../../../gn:default_deps",
+    "../../../../include/perfetto/ext/traced",
+    "../../../../protos/perfetto/trace:zero",
+    "../../../../protos/perfetto/trace/system_info:zero",
+    "../../../base",
+  ]
+  sources = [
+    "system_info_data_source.cc",
+    "system_info_data_source.h",
+  ]
+}
+
+perfetto_unittest_source_set("unittests") {
+  testonly = true
+  deps = [
+    ":system_info",
+    "../../../../gn:default_deps",
+    "../../../../gn:gtest_and_gmock",
+    "../../../../protos/perfetto/trace/system_info:cpp",
+    "../../../../src/tracing/test:test_support",
+  ]
+  sources = [ "system_info_data_source_unittest.cc" ]
+}
diff --git a/src/traced/probes/system_info/system_info_data_source.cc b/src/traced/probes/system_info/system_info_data_source.cc
new file mode 100644
index 0000000..98dd627
--- /dev/null
+++ b/src/traced/probes/system_info/system_info_data_source.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2020 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/traced/probes/system_info/system_info_data_source.h"
+
+#include "perfetto/base/time.h"
+#include "perfetto/ext/base/file_utils.h"
+#include "perfetto/ext/base/string_splitter.h"
+#include "perfetto/ext/base/string_utils.h"
+
+#include "protos/perfetto/trace/system_info/cpu_info.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+
+namespace {
+
+// Key for default processor string in /proc/cpuinfo as seen on arm. Note the
+// uppercase P.
+const char kDefaultProcessor[] = "Processor";
+
+// Key for processor entry in /proc/cpuinfo. Used to determine whether a group
+// of lines describes a CPU.
+const char kProcessor[] = "processor";
+
+void FillCpuFrequencies(protos::pbzero::CpuInfo_Cpu* cpu,
+                        const std::string& sys_cpu_frequencies) {
+  base::StringSplitter frequencies(sys_cpu_frequencies, ' ');
+  while (frequencies.Next()) {
+    auto frequency = base::StringToUInt32(frequencies.cur_token());
+    if (frequency.has_value())
+      cpu->add_frequencies(frequency.value());
+  }
+}
+
+}  // namespace
+
+// static
+const ProbesDataSource::Descriptor SystemInfoDataSource::descriptor = {
+    /* name */ "linux.system_info",
+    /* flags */ Descriptor::kFlagsNone,
+};
+
+SystemInfoDataSource::SystemInfoDataSource(TracingSessionID session_id,
+                                           std::unique_ptr<TraceWriter> writer)
+    : ProbesDataSource(session_id, &descriptor), writer_(std::move(writer)) {}
+
+void SystemInfoDataSource::Start() {
+  auto packet = writer_->NewTracePacket();
+  packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
+  auto* cpu_info = packet->set_cpu_info();
+
+  // Parse /proc/cpuinfo which contains groups of "key\t: value" lines separated
+  // by an empty line. Each group represents a CPU. See the full example in the
+  // unittest.
+  std::string proc_cpu_info = ReadFile("/proc/cpuinfo");
+  std::string::iterator line_start = proc_cpu_info.begin();
+  std::string::iterator line_end = proc_cpu_info.end();
+  std::string default_processor = "unknown";
+  std::string cpu_index = "";
+  int next_cpu_index = 0;
+  while (line_start != proc_cpu_info.end()) {
+    line_end = find(line_start, proc_cpu_info.end(), '\n');
+    if (line_end == proc_cpu_info.end())
+      break;
+    std::string line = std::string(line_start, line_end);
+    line_start = line_end + 1;
+    if (line.empty() && !cpu_index.empty()) {
+      PERFETTO_DCHECK(cpu_index == std::to_string(next_cpu_index));
+      auto* cpu = cpu_info->add_cpus();
+      cpu->set_processor(default_processor);
+      std::string sys_cpu_frequencies =
+          ReadFile("/sys/devices/system/cpu/cpu" + cpu_index +
+                   "/cpufreq/scaling_available_frequencies");
+      FillCpuFrequencies(cpu, sys_cpu_frequencies);
+      cpu_index = "";
+      next_cpu_index++;
+      continue;
+    }
+    auto splits = base::SplitString(line, ":");
+    if (splits.size() != 2)
+      continue;
+    std::string key =
+        base::StripSuffix(base::StripChars(splits[0], "\t", ' '), " ");
+    std::string value = base::StripPrefix(splits[1], " ");
+    if (key == kDefaultProcessor)
+      default_processor = value;
+    else if (key == kProcessor)
+      cpu_index = value;
+  }
+
+  packet->Finalize();
+  writer_->Flush();
+}
+
+void SystemInfoDataSource::Flush(FlushRequestID,
+                                 std::function<void()> callback) {
+  writer_->Flush(callback);
+}
+
+std::string SystemInfoDataSource::ReadFile(std::string path) {
+  std::string contents;
+  if (!base::ReadFile(path, &contents))
+    return "";
+  return contents;
+}
+
+}  // namespace perfetto
diff --git a/src/traced/probes/system_info/system_info_data_source.h b/src/traced/probes/system_info/system_info_data_source.h
new file mode 100644
index 0000000..c3d34be
--- /dev/null
+++ b/src/traced/probes/system_info/system_info_data_source.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 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_TRACED_PROBES_SYSTEM_INFO_SYSTEM_INFO_DATA_SOURCE_H_
+#define SRC_TRACED_PROBES_SYSTEM_INFO_SYSTEM_INFO_DATA_SOURCE_H_
+
+#include <memory>
+
+#include "perfetto/ext/tracing/core/trace_writer.h"
+#include "src/traced/probes/probes_data_source.h"
+
+namespace perfetto {
+
+class SystemInfoDataSource : public ProbesDataSource {
+ public:
+  static const ProbesDataSource::Descriptor descriptor;
+
+  SystemInfoDataSource(TracingSessionID, std::unique_ptr<TraceWriter> writer);
+
+  // ProbesDataSource implementation.
+  void Start() override;
+  void Flush(FlushRequestID, std::function<void()> callback) override;
+
+  // Virtual for testing.
+  virtual std::string ReadFile(std::string path);
+
+ private:
+  std::unique_ptr<TraceWriter> writer_;
+};
+
+}  // namespace perfetto
+
+#endif  // SRC_TRACED_PROBES_SYSTEM_INFO_SYSTEM_INFO_DATA_SOURCE_H_
diff --git a/src/traced/probes/system_info/system_info_data_source_unittest.cc b/src/traced/probes/system_info/system_info_data_source_unittest.cc
new file mode 100644
index 0000000..dd5d856
--- /dev/null
+++ b/src/traced/probes/system_info/system_info_data_source_unittest.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2020 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/traced/probes/system_info/system_info_data_source.h"
+#include "src/tracing/core/trace_writer_for_testing.h"
+#include "test/gtest_and_gmock.h"
+
+#include "protos/perfetto/trace/system_info/cpu_info.gen.h"
+
+using ::testing::AnyOf;
+using ::testing::ElementsAre;
+using ::testing::Return;
+
+namespace perfetto {
+namespace {
+
+const char kMockCpuInfoAndroid[] = R"(
+Processor	: AArch64 Processor rev 13 (aarch64)
+processor	: 0
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x7
+CPU part	: 0x803
+CPU revision	: 12
+
+processor	: 1
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x7
+CPU part	: 0x803
+CPU revision	: 12
+
+processor	: 2
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x7
+CPU part	: 0x803
+CPU revision	: 12
+
+processor	: 3
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x7
+CPU part	: 0x803
+CPU revision	: 12
+
+processor	: 4
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x7
+CPU part	: 0x803
+CPU revision	: 12
+
+processor	: 5
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x7
+CPU part	: 0x803
+CPU revision	: 12
+
+processor	: 6
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x6
+CPU part	: 0x802
+CPU revision	: 13
+
+processor	: 7
+BogoMIPS	: 38.00
+Features	: fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp
+CPU implementer	: 0x51
+CPU architecture: 8
+CPU variant	: 0x6
+CPU part	: 0x802
+CPU revision	: 13
+
+Hardware	: Qualcomm Technologies, Inc SDM670
+
+)";
+
+const char kMockCpuFrequenciesAndroidLittleCore[] = R"(
+300000 576000 748800 998400 1209600 1324800 1516800 1612800 1708800 )";
+
+const char kMockCpuFrequenciesAndroidBigCore[] = R"(
+300000 652800 825600 979200 1132800 1363200 1536000 1747200 1843200 1996800 )";
+
+class TestSystemInfoDataSource : public SystemInfoDataSource {
+ public:
+  TestSystemInfoDataSource(std::unique_ptr<TraceWriter> writer)
+      : SystemInfoDataSource(/* session_id */ 0, std::move(writer)) {}
+
+  MOCK_METHOD1(ReadFile, std::string(std::string));
+};
+
+class SystemInfoDataSourceTest : public ::testing::Test {
+ protected:
+  std::unique_ptr<TestSystemInfoDataSource> GetSystemInfoDataSource() {
+    auto writer =
+        std::unique_ptr<TraceWriterForTesting>(new TraceWriterForTesting());
+    writer_raw_ = writer.get();
+    auto instance = std::unique_ptr<TestSystemInfoDataSource>(
+        new TestSystemInfoDataSource(std::move(writer)));
+    return instance;
+  }
+
+  TraceWriterForTesting* writer_raw_ = nullptr;
+};
+
+TEST_F(SystemInfoDataSourceTest, CpuInfoAndroid) {
+  auto data_source = GetSystemInfoDataSource();
+  EXPECT_CALL(*data_source, ReadFile("/proc/cpuinfo"))
+      .WillOnce(Return(kMockCpuInfoAndroid));
+  auto cpu_freq_path = [](uint32_t cpu) {
+    return "/sys/devices/system/cpu/cpu" + std::to_string(cpu) +
+           "/cpufreq/scaling_available_frequencies";
+  };
+  EXPECT_CALL(*data_source, ReadFile(AnyOf(cpu_freq_path(0), cpu_freq_path(1),
+                                           cpu_freq_path(2), cpu_freq_path(3),
+                                           cpu_freq_path(4), cpu_freq_path(5))))
+      .Times(6)
+      .WillRepeatedly(Return(kMockCpuFrequenciesAndroidLittleCore));
+  EXPECT_CALL(*data_source, ReadFile(AnyOf(cpu_freq_path(6), cpu_freq_path(7))))
+      .Times(2)
+      .WillRepeatedly(Return(kMockCpuFrequenciesAndroidBigCore));
+  data_source->Start();
+
+  protos::gen::TracePacket packet = writer_raw_->GetOnlyTracePacket();
+  ASSERT_TRUE(packet.has_cpu_info());
+  auto cpu_info = packet.cpu_info();
+  ASSERT_EQ(cpu_info.cpus_size(), 8);
+  for (size_t i = 0; i < 6; i++) {
+    auto cpu = cpu_info.cpus()[i];
+    ASSERT_EQ(cpu.processor(), "AArch64 Processor rev 13 (aarch64)");
+    ASSERT_THAT(cpu.frequencies(),
+                ElementsAre(300000, 576000, 748800, 998400, 1209600, 1324800,
+                            1516800, 1612800, 1708800));
+  }
+  for (size_t i = 6; i < 8; i++) {
+    auto cpu = cpu_info.cpus()[i];
+    ASSERT_EQ(cpu.processor(), "AArch64 Processor rev 13 (aarch64)");
+    ASSERT_THAT(cpu.frequencies(),
+                ElementsAre(300000, 652800, 825600, 979200, 1132800, 1363200,
+                            1536000, 1747200, 1843200, 1996800));
+  }
+}
+
+}  // namespace
+}  // namespace perfetto
diff --git a/tools/gen_merged_protos b/tools/gen_merged_protos
index b6b3eaa..37306ed 100755
--- a/tools/gen_merged_protos
+++ b/tools/gen_merged_protos
@@ -93,6 +93,7 @@
     'protos/perfetto/trace/ps/process_tree.proto',
     'protos/perfetto/trace/sys_stats/sys_stats.proto',
     'protos/perfetto/trace/system_info.proto',
+    'protos/perfetto/trace/system_info/cpu_info.proto',
     'protos/perfetto/trace/trace.proto',
     'protos/perfetto/trace/trace_packet.proto',
     'protos/perfetto/trace/trace_packet_defaults.proto',