1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.android.car.kitchensink.telemetry;
18 
19 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.ACTIVITY_FOREGROUND_STATE_CHANGED;
20 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.ANR_OCCURRED;
21 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_CRASH_OCCURRED;
22 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.APP_START_MEMORY_STATE_CAPTURED;
23 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_CPU_TIME;
24 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_SNAPSHOT;
25 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_STATE;
26 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_START_TIME;
27 import static android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.WTF_OCCURRED;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.annotation.RawRes;
32 import android.app.ActivityManager;
33 import android.car.VehiclePropertyIds;
34 import android.car.telemetry.CarTelemetryManager;
35 import android.car.telemetry.TelemetryProto;
36 import android.car.telemetry.TelemetryProto.ConnectivityPublisher;
37 import android.os.Bundle;
38 import android.os.PersistableBundle;
39 import android.util.Log;
40 import android.view.LayoutInflater;
41 import android.view.View;
42 import android.view.ViewGroup;
43 import android.widget.Button;
44 import android.widget.TextView;
45 
46 import androidx.fragment.app.Fragment;
47 
48 import com.google.android.car.kitchensink.KitchenSinkActivity;
49 import com.google.android.car.kitchensink.R;
50 import com.google.protobuf.InvalidProtocolBufferException;
51 
52 import java.io.BufferedReader;
53 import java.io.File;
54 import java.io.IOException;
55 import java.io.InputStream;
56 import java.io.InputStreamReader;
57 import java.nio.file.Files;
58 import java.nio.file.Path;
59 import java.nio.file.Paths;
60 import java.time.LocalDateTime;
61 import java.time.format.DateTimeFormatter;
62 import java.util.concurrent.Executor;
63 import java.util.concurrent.Executors;
64 
65 public class CarTelemetryTestFragment extends Fragment {
66     private static final String TAG = CarTelemetryTestFragment.class.getSimpleName();
67 
68     private static final int SCRIPT_EXECUTION_PRIORITY_HIGH = 0;
69     private static final int SCRIPT_EXECUTION_PRIORITY_LOW = 100;
70 
71     /** Vehicle property via gear change section. */
72     private static final String LUA_SCRIPT_ON_GEAR_CHANGE =
73             "function onGearChange(published_data, state)\n"
74                     + "    t = {}\n"
75                     + "    for k, v in ipairs(published_data) do\n"
76                     + "        t['#' .. k] = 'Gear: ' .. v['vp.intVal'] \n"
77                     + "        log(v[\"vp.intVal\"])\n"
78                     + "    end\n"
79                     + "    on_metrics_report(t)\n"
80                     + "end\n";
81 
82     private static final TelemetryProto.Publisher VEHICLE_PROPERTY_PUBLISHER =
83             TelemetryProto.Publisher.newBuilder()
84                     .setVehicleProperty(
85                             TelemetryProto.VehiclePropertyPublisher.newBuilder()
86                                     .setVehiclePropertyId(VehiclePropertyIds.GEAR_SELECTION)
87                                     .setReadRate(0f)
88                                     .build())
89                     .build();
90     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_ON_GEAR_CHANGE_V1 =
91             TelemetryProto.MetricsConfig.newBuilder()
92                     .setName("my_metrics_config")
93                     .setVersion(1)
94                     .setScript(LUA_SCRIPT_ON_GEAR_CHANGE)
95                     .addSubscribers(
96                             TelemetryProto.Subscriber.newBuilder()
97                                     .setHandler("onGearChange")
98                                     .setPublisher(VEHICLE_PROPERTY_PUBLISHER)
99                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
100                     .build();
101     private static final String ON_GEAR_CHANGE_CONFIG_NAME =
102             METRICS_CONFIG_ON_GEAR_CHANGE_V1.getName();
103 
104     /** ProcessMemoryState section. */
105     private static final String LUA_SCRIPT_ON_PROCESS_MEMORY_STATE = new StringBuilder()
106             .append("function calculateAverage(tbl)\n")
107             .append("    local sum = 0\n")
108             .append("    local size = 0\n")
109             .append("    for _, value in ipairs(tbl) do\n")
110             .append("        sum = sum + value\n")
111             .append("        size = size + 1\n")
112             .append("    end\n")
113             .append("    return sum/size\n")
114             .append("end\n")
115             .append("function onProcessMemory(published_data, state)\n")
116             .append("    local result = {}\n")
117             .append("    result.page_fault_avg = calculateAverage("
118                     + "published_data['stats.page_fault'])\n")
119             .append("    result.major_page_fault_avg = calculateAverage("
120                     + "published_data['stats.page_major_fault'])\n")
121             .append("    result.oom_adj_score_avg = calculateAverage("
122                     + "published_data['stats.oom_adj_score'])\n")
123             .append("    result.rss_in_bytes_avg = calculateAverage("
124                     + "published_data['stats.rss_in_bytes'])\n")
125             .append("    result.swap_in_bytes_avg = calculateAverage("
126                     + "published_data['stats.swap_in_bytes'])\n")
127             .append("    result.cache_in_bytes_avg = calculateAverage("
128                     + "published_data['stats.cache_in_bytes'])\n")
129             .append("    on_script_finished(result)\n")
130             .append("end\n")
131             .toString();
132     private static final TelemetryProto.Publisher PROCESS_MEMORY_PUBLISHER =
133             TelemetryProto.Publisher.newBuilder()
134                     .setStats(
135                             TelemetryProto.StatsPublisher.newBuilder()
136                                     .setSystemMetric(PROCESS_MEMORY_STATE))
137                     .build();
138     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_PROCESS_MEMORY_V1 =
139             TelemetryProto.MetricsConfig.newBuilder()
140                     .setName("process_memory_metrics_config")
141                     .setVersion(1)
142                     .setScript(LUA_SCRIPT_ON_PROCESS_MEMORY_STATE)
143                     .addSubscribers(
144                             TelemetryProto.Subscriber.newBuilder()
145                                     .setHandler("onProcessMemory")
146                                     .setPublisher(PROCESS_MEMORY_PUBLISHER)
147                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
148                     .build();
149     private static final String PROCESS_MEMORY_CONFIG_NAME =
150             METRICS_CONFIG_PROCESS_MEMORY_V1.getName();
151 
152     /** AppStartMemoryStateCaptured section. */
153     private static final String LUA_SCRIPT_ON_APP_START_MEMORY_STATE_CAPTURED = new StringBuilder()
154             .append("function calculateAverage(tbl)\n")
155             .append("    local sum = 0\n")
156             .append("    local size = 0\n")
157             .append("    for _, value in ipairs(tbl) do\n")
158             .append("        sum = sum + value\n")
159             .append("        size = size + 1\n")
160             .append("    end\n")
161             .append("    return sum/size\n")
162             .append("end\n")
163             .append("function onAppStartMemoryStateCaptured(published_data, state)\n")
164             .append("    local result = {}\n")
165             .append("    result.uid = published_data['stats.uid']\n")
166             .append("    result.page_fault_avg = calculateAverage("
167                     + "published_data['stats.page_fault'])\n")
168             .append("    result.major_page_fault_avg = calculateAverage("
169                     + "published_data['stats.page_major_fault'])\n")
170             .append("    result.rss_in_bytes_avg = calculateAverage("
171                     + "published_data['stats.rss_in_bytes'])\n")
172             .append("    result.swap_in_bytes_avg = calculateAverage("
173                     + "published_data['stats.swap_in_bytes'])\n")
174             .append("    result.cache_in_bytes_avg = calculateAverage("
175                     + "published_data['stats.cache_in_bytes'])\n")
176             .append("    on_script_finished(result)\n")
177             .append("end\n")
178             .toString();
179     private static final TelemetryProto.Publisher APP_START_MEMORY_STATE_CAPTURED_PUBLISHER =
180             TelemetryProto.Publisher.newBuilder()
181                     .setStats(
182                             TelemetryProto.StatsPublisher.newBuilder()
183                                     .setSystemMetric(APP_START_MEMORY_STATE_CAPTURED))
184                     .build();
185     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_APP_START_MEMORY_V1 =
186             TelemetryProto.MetricsConfig.newBuilder()
187                     .setName("app_start_memory_metrics_config")
188                     .setVersion(1)
189                     .setScript(LUA_SCRIPT_ON_APP_START_MEMORY_STATE_CAPTURED)
190                     .addSubscribers(
191                             TelemetryProto.Subscriber.newBuilder()
192                                     .setHandler("onAppStartMemoryStateCaptured")
193                                     .setPublisher(APP_START_MEMORY_STATE_CAPTURED_PUBLISHER)
194                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
195                     .build();
196     private static final String APP_START_MEMORY_STATE_CAPTURED_CONFIG_NAME =
197             METRICS_CONFIG_APP_START_MEMORY_V1.getName();
198 
199     /** ActivityForegroundStateChanged section. */
200     private static final String LUA_SCRIPT_ON_ACTIVITY_FOREGROUND_STATE_CHANGED =
201             new StringBuilder()
202                     .append("function onActivityForegroundStateChanged(published_data, state)\n")
203                     .append("    local result = {}\n")
204                     .append("    local n = 0\n")
205                     .append("    for k, v in pairs(published_data) do\n")
206                     .append("        result[k] = v[1]\n")
207                     .append("        n = n + 1\n")
208                     .append("    end\n")
209                     .append("    result.n = n\n")
210                     .append("    on_script_finished(result)\n")
211                     .append("end\n")
212                     .toString();
213 
214     private static final TelemetryProto.Publisher ACTIVITY_FOREGROUND_STATE_CHANGED_PUBLISHER =
215             TelemetryProto.Publisher.newBuilder()
216                     .setStats(
217                             TelemetryProto.StatsPublisher.newBuilder()
218                                     .setSystemMetric(ACTIVITY_FOREGROUND_STATE_CHANGED))
219                     .build();
220     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_ACTIVITY_FOREGROUND_STATE_V1 =
221             TelemetryProto.MetricsConfig.newBuilder()
222                     .setName("activity_foreground_state_changed_config")
223                     .setVersion(1)
224                     .setScript(LUA_SCRIPT_ON_ACTIVITY_FOREGROUND_STATE_CHANGED)
225                     .addSubscribers(
226                             TelemetryProto.Subscriber.newBuilder()
227                                     .setHandler("onActivityForegroundStateChanged")
228                                     .setPublisher(ACTIVITY_FOREGROUND_STATE_CHANGED_PUBLISHER)
229                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
230                     .build();
231     private static final String ACTIVITY_FOREGROUND_STATE_CHANGED_CONFIG_NAME =
232             METRICS_CONFIG_ACTIVITY_FOREGROUND_STATE_V1.getName();
233 
234     /** ProcessCpuTime section */
235     private static final String LUA_SCRIPT_ON_PROCESS_CPU_TIME =
236             new StringBuilder()
237                     .append("function onProcessCpuTime(published_data, state)\n")
238                     .append("    local result = {}\n")
239                     .append("    local n = 0\n")
240                     .append("    for k, v in pairs(published_data) do\n")
241                     .append("        result[k] = v[1]\n")
242                     .append("        n = n + 1\n")
243                     .append("    end\n")
244                     .append("    result.n = n\n")
245                     .append("    on_script_finished(result)\n")
246                     .append("end\n")
247                     .toString();
248 
249     private static final TelemetryProto.Publisher PROCESS_CPU_TIME_PUBLISHER =
250             TelemetryProto.Publisher.newBuilder()
251                     .setStats(
252                             TelemetryProto.StatsPublisher.newBuilder()
253                                     .setSystemMetric(PROCESS_CPU_TIME))
254                     .build();
255     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_PROCESS_CPU_TIME_V1 =
256             TelemetryProto.MetricsConfig.newBuilder()
257                     .setName("process_cpu_time_config")
258                     .setVersion(1)
259                     .setScript(LUA_SCRIPT_ON_PROCESS_CPU_TIME)
260                     .addSubscribers(
261                             TelemetryProto.Subscriber.newBuilder()
262                                     .setHandler("onProcessCpuTime")
263                                     .setPublisher(PROCESS_CPU_TIME_PUBLISHER)
264                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
265                     .build();
266     private static final String PROCESS_CPU_TIME_CONFIG_NAME =
267             METRICS_CONFIG_PROCESS_CPU_TIME_V1.getName();
268 
269     /** AppCrashOccurred section */
270     private static final String LUA_SCRIPT_ON_APP_CRASH_OCCURRED =
271             new StringBuilder()
272                     .append("function onAppCrashOccurred(published_data, state)\n")
273                     .append("    local result = {}\n")
274                     .append("    for k, v in pairs(published_data) do\n")
275                     .append("        result[k] = v[1]\n")
276                     .append("    end\n")
277                     .append("    on_script_finished(result)\n")
278                     .append("end\n")
279                     .toString();
280 
281     private static final TelemetryProto.Publisher APP_CRASH_OCCURRED_PUBLISHER =
282             TelemetryProto.Publisher.newBuilder()
283                     .setStats(
284                             TelemetryProto.StatsPublisher.newBuilder()
285                                     .setSystemMetric(APP_CRASH_OCCURRED))
286                     .build();
287     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_APP_CRASH_OCCURRED_V1 =
288             TelemetryProto.MetricsConfig.newBuilder()
289                     .setName("app_crash_occurred_config")
290                     .setVersion(1)
291                     .setScript(LUA_SCRIPT_ON_APP_CRASH_OCCURRED)
292                     .addSubscribers(
293                             TelemetryProto.Subscriber.newBuilder()
294                                     .setHandler("onAppCrashOccurred")
295                                     .setPublisher(APP_CRASH_OCCURRED_PUBLISHER)
296                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
297                     .build();
298     private static final String APP_CRASH_OCCURRED_CONFIG_NAME =
299             METRICS_CONFIG_APP_CRASH_OCCURRED_V1.getName();
300 
301     /** ANROccurred section */
302     private static final String LUA_SCRIPT_ON_ANR_OCCURRED =
303             new StringBuilder()
304                     .append("function onAnrOccurred(published_data, state)\n")
305                     .append("    local result = {}\n")
306                     .append("    for k, v in pairs(published_data) do\n")
307                     .append("        result[k] = v[1]\n")
308                     .append("    end\n")
309                     .append("    on_script_finished(result)\n")
310                     .append("end\n")
311                     .toString();
312 
313     private static final TelemetryProto.Publisher ANR_OCCURRED_PUBLISHER =
314             TelemetryProto.Publisher.newBuilder()
315                     .setStats(
316                             TelemetryProto.StatsPublisher.newBuilder()
317                                     .setSystemMetric(ANR_OCCURRED))
318                     .build();
319     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_ANR_OCCURRED_V1 =
320             TelemetryProto.MetricsConfig.newBuilder()
321                     .setName("anr_occurred_config")
322                     .setVersion(1)
323                     .setScript(LUA_SCRIPT_ON_ANR_OCCURRED)
324                     .addSubscribers(
325                             TelemetryProto.Subscriber.newBuilder()
326                                     .setHandler("onAnrOccurred")
327                                     .setPublisher(ANR_OCCURRED_PUBLISHER)
328                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
329                     .build();
330     private static final String ANR_OCCURRED_CONFIG_NAME = METRICS_CONFIG_ANR_OCCURRED_V1.getName();
331 
332     /** WTFOccurred section */
333     private static final String LUA_SCRIPT_ON_WTF_OCCURRED =
334             new StringBuilder()
335                     .append("function onWtfOccurred(published_data, state)\n")
336                     .append("    local result = {}\n")
337                     .append("    for k, v in pairs(published_data) do\n")
338                     .append("        result[k] = v[1]\n")
339                     .append("    end\n")
340                     .append("    on_script_finished(result)\n")
341                     .append("end\n")
342                     .toString();
343 
344     private static final TelemetryProto.Publisher WTF_OCCURRED_PUBLISHER =
345             TelemetryProto.Publisher.newBuilder()
346                     .setStats(
347                             TelemetryProto.StatsPublisher.newBuilder()
348                                     .setSystemMetric(WTF_OCCURRED))
349                     .build();
350     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_WTF_OCCURRED_V1 =
351             TelemetryProto.MetricsConfig.newBuilder()
352                     .setName("wtf_occurred_config")
353                     .setVersion(1)
354                     .setScript(LUA_SCRIPT_ON_WTF_OCCURRED)
355                     .addSubscribers(
356                             TelemetryProto.Subscriber.newBuilder()
357                                     .setHandler("onWtfOccurred")
358                                     .setPublisher(WTF_OCCURRED_PUBLISHER)
359                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
360                     .build();
361     private static final String WTF_OCCURRED_CONFIG_NAME = METRICS_CONFIG_WTF_OCCURRED_V1.getName();
362 
363     private static final TelemetryProto.Publisher WIFI_NETSTATS_PUBLISHER =
364             TelemetryProto.Publisher.newBuilder()
365                     .setConnectivity(
366                             ConnectivityPublisher.newBuilder()
367                                     .setTransport(ConnectivityPublisher.Transport.TRANSPORT_WIFI)
368                                     .setOemType(ConnectivityPublisher.OemType.OEM_NONE))
369                     .build();
370     // This config uses the script "R.raw.telemetry_stats_and_connectivity_script".
371     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_WIFI_TOP_CONSUMERS =
372             TelemetryProto.MetricsConfig.newBuilder()
373                     .setName("wifi_top_consumers")
374                     .setVersion(1)
375                     .addSubscribers(
376                             TelemetryProto.Subscriber.newBuilder()
377                                     .setHandler("onWifiNetstatsForTopConsumers")
378                                     .setPublisher(WIFI_NETSTATS_PUBLISHER)
379                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
380                     .build();
381     private static final String WIFI_TOP_CONSUMERS_CONFIG_NAME =
382             METRICS_CONFIG_WIFI_TOP_CONSUMERS.getName();
383 
384     // This config uses the script "R.raw.telemetry_driving_sessions_script".
385     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_DRIVING_SESSIONS =
386             TelemetryProto.MetricsConfig.newBuilder()
387                     .setName("wifi_stats_with_driving_sessions")
388                     .setVersion(1)
389                     .addSubscribers(
390                             TelemetryProto.Subscriber.newBuilder()
391                                     .setHandler("onWifiStatsForDrivingSessions")
392                                     .setPublisher(WIFI_NETSTATS_PUBLISHER)
393                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
394                     .build();
395     private static final String WIFI_STATS_DRIVING_SESSIONS_CONFIG_NAME =
396             METRICS_CONFIG_DRIVING_SESSIONS.getName();
397 
398     /**
399      * PROCESS_CPU_TIME + PROCESS_MEMORY + WIFI_NETSTATS section. Reuses the same publisher
400      * configuration that were defined above for PROCESS_CPU_TIME, PROCESS_MEMORY, and
401      * WIFI_NETSTATS. Its script is R.raw.telemetry_stats_and_connectivity_script which is loaded at
402      * runtime. The script produces a final report when it receives atoms PROCESS_MEMORY and
403      * PROCESS_CPU_TIME, and more than 5 pieces of data from connectivity publisher.
404      */
405     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_STATS_AND_CONNECTIVITY_V1 =
406             TelemetryProto.MetricsConfig.newBuilder()
407                     .setName("stats_and_connectivity_metrics_config")
408                     .setVersion(1)
409                     .addSubscribers(
410                             TelemetryProto.Subscriber.newBuilder()
411                                     .setHandler("onProcessMemory")
412                                     .setPublisher(PROCESS_MEMORY_PUBLISHER)
413                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
414                     .addSubscribers(
415                             TelemetryProto.Subscriber.newBuilder()
416                                     .setHandler("onProcessCpuTime")
417                                     .setPublisher(PROCESS_CPU_TIME_PUBLISHER)
418                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
419                     .addSubscribers(
420                             TelemetryProto.Subscriber.newBuilder()
421                                     .setHandler("onWifiNetstats")
422                                     .setPublisher(WIFI_NETSTATS_PUBLISHER)
423                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
424                     .build();
425 
426     private static final String STATS_AND_CONNECTIVITY_CONFIG_NAME =
427             METRICS_CONFIG_STATS_AND_CONNECTIVITY_V1.getName();
428 
429     /** MemoryPublisher section. */
430     private static final String LUA_SCRIPT_ON_MEMORY =
431             new StringBuilder()
432                     .append("function onMemory(published_data, state)\n")
433                     .append("    local iterations = state['iterations']\n")
434                     .append("    if iterations == nil then\n")
435                     .append("        iterations = 0\n")
436                     .append("    end\n")
437                     .append("    state['iterations'] = iterations + 1\n")
438                     .append("    local meminfo = published_data['mem.meminfo']\n")
439                     .append("    local available_memory = string.match(meminfo, "
440                             + "'.*MemAvailable:%s*(%d+).*')\n")
441                     .append("    local mem_key = 'available_memory_' .. iterations\n")
442                     .append("    published_data[mem_key] = available_memory\n")
443                     .append("    published_data['mem.meminfo'] = nil\n")
444                     .append("    on_metrics_report(published_data, state)\n")
445                     .append("end\n")
446                     .toString();
447     private static final TelemetryProto.Publisher MEMORY_PUBLISHER =
448             TelemetryProto.Publisher.newBuilder()
449                     .setMemory(
450                             TelemetryProto.MemoryPublisher.newBuilder()
451                                     .setReadIntervalSec(3)
452                                     .setMaxSnapshots(3)
453                                     .setMaxPendingTasks(10)
454                                     .addPackageNames("com.android.car")
455                                     .addPackageNames("com.android.car.scriptexecutor")
456                                     .build())
457                     .build();
458     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_MEMORY_V1 =
459             TelemetryProto.MetricsConfig.newBuilder()
460                     .setName("memory_config")
461                     .setVersion(1)
462                     .setScript(LUA_SCRIPT_ON_MEMORY)
463                     .addSubscribers(
464                             TelemetryProto.Subscriber.newBuilder()
465                                     .setHandler("onMemory")
466                                     .setPublisher(MEMORY_PUBLISHER)
467                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
468                     .build();
469     private static final String MEMORY_CONFIG_NAME =
470             METRICS_CONFIG_MEMORY_V1.getName();
471 
472     /** ProcessMemorySnapshot section. */
473     private static final String LUA_SCRIPT_ON_PROCESS_MEMORY_SNAPSHOT = new StringBuilder()
474             .append("function onProcessMemorySnapshot(published_data, state)\n")
475             .append("    on_script_finished(published_data)\n")
476             .append("end\n")
477             .toString();
478     private static final TelemetryProto.Publisher PROCESS_MEMORY_SNAPSHOT_PUBLISHER =
479             TelemetryProto.Publisher.newBuilder()
480                     .setStats(
481                             TelemetryProto.StatsPublisher.newBuilder()
482                                     .setSystemMetric(PROCESS_MEMORY_SNAPSHOT))
483                     .build();
484     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1 =
485             TelemetryProto.MetricsConfig.newBuilder()
486                     .setName("process_memory_snapshot_metrics_config")
487                     .setVersion(1)
488                     .setScript(LUA_SCRIPT_ON_PROCESS_MEMORY_SNAPSHOT)
489                     .addSubscribers(
490                             TelemetryProto.Subscriber.newBuilder()
491                                     .setHandler("onProcessMemorySnapshot")
492                                     .setPublisher(PROCESS_MEMORY_SNAPSHOT_PUBLISHER)
493                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
494                     .build();
495     private static final String PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME =
496             METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1.getName();
497 
498     /** ProcessStartTime section. */
499     private static final String LUA_SCRIPT_ON_PROCESS_START_TIME = new StringBuilder()
500             .append("function onProcessStartTime(published_data, state)\n")
501             .append("    on_script_finished(published_data)\n")
502             .append("end\n")
503             .toString();
504     private static final TelemetryProto.Publisher PROCESS_START_TIME_PUBLISHER =
505             TelemetryProto.Publisher.newBuilder()
506                     .setStats(
507                             TelemetryProto.StatsPublisher.newBuilder()
508                                     .setSystemMetric(PROCESS_START_TIME))
509                     .build();
510     private static final TelemetryProto.MetricsConfig METRICS_CONFIG_PROCESS_START_TIME_V1 =
511             TelemetryProto.MetricsConfig.newBuilder()
512                     .setName("process_start_time_metrics_config")
513                     .setVersion(1)
514                     .setScript(LUA_SCRIPT_ON_PROCESS_START_TIME)
515                     .addSubscribers(
516                             TelemetryProto.Subscriber.newBuilder()
517                                     .setHandler("onProcessStartTime")
518                                     .setPublisher(PROCESS_START_TIME_PUBLISHER)
519                                     .setPriority(SCRIPT_EXECUTION_PRIORITY_HIGH))
520                     .build();
521     private static final String PROCESS_START_TIME_CONFIG_NAME =
522                 METRICS_CONFIG_PROCESS_START_TIME_V1.getName();
523 
524     private final Executor mExecutor = Executors.newSingleThreadExecutor();
525 
526     private boolean mReceiveReportNotification = false;
527     private CarTelemetryManager mCarTelemetryManager;
528     private FinishedReportListenerImpl mListener;
529     private AddMetricsConfigCallbackImpl mAddMetricsConfigCallback;
530     private KitchenSinkActivity mActivity;
531     private TextView mOutputTextView;
532     private Button mTootleConfigsBtn;
533     private Button mEnableReportNotificationButton;
534     private View mConfigButtonsView; // MetricsConfig buttons
535 
536     @Override
onCreate(@ullable Bundle savedInstanceState)537     public void onCreate(@Nullable Bundle savedInstanceState) {
538         mActivity = (KitchenSinkActivity) getActivity();
539         mCarTelemetryManager = mActivity.getCarTelemetryManager();
540         mListener = new FinishedReportListenerImpl();
541         mAddMetricsConfigCallback = new AddMetricsConfigCallbackImpl();
542         super.onCreate(savedInstanceState);
543     }
544 
545     @Nullable
546     @Override
onCreateView( @onNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)547     public View onCreateView(
548             @NonNull LayoutInflater inflater,
549             @Nullable ViewGroup container,
550             @Nullable Bundle savedInstanceState) {
551         View view = inflater.inflate(R.layout.car_telemetry_test, container, false);
552         mOutputTextView = view.findViewById(R.id.output_textview);
553         mConfigButtonsView = view.findViewById(R.id.metrics_config_buttons_view);
554         mTootleConfigsBtn = view.findViewById(R.id.toggle_metrics_configs_btn);
555         mTootleConfigsBtn.setOnClickListener(this::toggleMetricsConfigButtons);
556         mEnableReportNotificationButton = view.findViewById(R.id.enable_report_notification_btn);
557         mEnableReportNotificationButton.setOnClickListener(this::enableReportNotification);
558         mEnableReportNotificationButton.setText(
559                 getString(R.string.receive_report_notification_text, mReceiveReportNotification));
560 
561         /** VehiclePropertyPublisher on_gear_change */
562         view.findViewById(R.id.send_on_gear_change_config)
563                 .setOnClickListener(this::onSendGearChangeConfigBtnClick);
564         view.findViewById(R.id.remove_on_gear_change_config)
565                 .setOnClickListener(this::onRemoveGearChangeConfigBtnClick);
566         view.findViewById(R.id.get_on_gear_change_report)
567                 .setOnClickListener(this::onGetGearChangeReportBtnClick);
568         /** StatsPublisher process_memory */
569         view.findViewById(R.id.send_on_process_memory_config)
570                 .setOnClickListener(this::onSendProcessMemoryConfigBtnClick);
571         view.findViewById(R.id.remove_on_process_memory_config)
572                 .setOnClickListener(this::onRemoveProcessMemoryConfigBtnClick);
573         view.findViewById(R.id.get_on_process_memory_report)
574                 .setOnClickListener(this::onGetProcessMemoryReportBtnClick);
575         /** StatsPublisher app_start_memory_state */
576         view.findViewById(R.id.send_on_app_start_memory_state_captured_config)
577                 .setOnClickListener(this::onSendAppStartMemoryStateCapturedConfigBtnClick);
578         view.findViewById(R.id.remove_on_app_start_memory_state_captured_config)
579                 .setOnClickListener(this::onRemoveAppStartMemoryStateCapturedConfigBtnClick);
580         view.findViewById(R.id.get_on_app_start_memory_state_captured_report)
581                 .setOnClickListener(this::onGetAppStartMemoryStateCapturedReportBtnClick);
582         /** StatsPublisher activity_foreground_state_change */
583         view.findViewById(R.id.send_on_activity_foreground_state_changed_config)
584                 .setOnClickListener(this::onSendActivityForegroundStateChangedConfigBtnClick);
585         view.findViewById(R.id.remove_on_activity_foreground_state_changed_config)
586                 .setOnClickListener(this::onRemoveActivityForegroundStateChangedConfigBtnClick);
587         view.findViewById(R.id.get_on_activity_foreground_state_changed_report)
588                 .setOnClickListener(this::onGetActivityForegroundStateChangedReportBtnClick);
589         /** StatsPublisher process_cpu_time */
590         view.findViewById(R.id.send_on_process_cpu_time_config)
591                 .setOnClickListener(this::onSendProcessCpuTimeConfigBtnClick);
592         view.findViewById(R.id.remove_on_process_cpu_time_config)
593                 .setOnClickListener(this::onRemoveProcessCpuTimeConfigBtnClick);
594         view.findViewById(R.id.get_on_process_cpu_time_report)
595                 .setOnClickListener(this::onGetProcessCpuTimeReportBtnClick);
596         /** StatsPublisher AppCrashOccurred section */
597         view.findViewById(R.id.send_on_app_crash_occurred_config)
598                 .setOnClickListener(this::onSendAppCrashOccurredConfigBtnClick);
599         view.findViewById(R.id.remove_on_app_crash_occurred_config)
600                 .setOnClickListener(this::onRemoveAppCrashOccurredConfigBtnClick);
601         view.findViewById(R.id.get_on_app_crash_occurred_report)
602                 .setOnClickListener(this::onGetAppCrashOccurredReportBtnClick);
603         /** StatsPublisher ANROccurred section */
604         view.findViewById(R.id.send_on_anr_occurred_config)
605                 .setOnClickListener(this::onSendAnrOccurredConfigBtnClick);
606         view.findViewById(R.id.remove_on_anr_occurred_config)
607                 .setOnClickListener(this::onRemoveAnrOccurredConfigBtnClick);
608         view.findViewById(R.id.get_on_anr_occurred_report)
609                 .setOnClickListener(this::onGetAnrOccurredReportBtnClick);
610         /** StatsPublisher WTFOccurred section */
611         view.findViewById(R.id.send_on_wtf_occurred_config)
612                 .setOnClickListener(this::onSendWtfOccurredConfigBtnClick);
613         view.findViewById(R.id.remove_on_wtf_occurred_config)
614                 .setOnClickListener(this::onRemoveWtfOccurredConfigBtnClick);
615         view.findViewById(R.id.get_on_wtf_occurred_report)
616                 .setOnClickListener(this::onGetWtfOccurredReportBtnClick);
617         /** ConnectivityPublisher wifi_netstats top consumers section */
618         view.findViewById(R.id.send_on_wifi_netstats_config)
619                 .setOnClickListener(this::onSendWifiNetstatsConfigBtnClick);
620         view.findViewById(R.id.remove_on_wifi_netstats_config)
621                 .setOnClickListener(this::onRemoveWifiNetstatsConfigBtnClick);
622         view.findViewById(R.id.get_on_wifi_netstats_report)
623                 .setOnClickListener(this::onGetWifiNetstatsReportBtnClick);
624         /** StatsPublisher + ConnectivityPublisher section */
625         view.findViewById(R.id.send_stats_and_connectivity_config)
626                 .setOnClickListener(this::onSendStatsAndConnectivityConfigBtnClick);
627         view.findViewById(R.id.remove_stats_and_connectivity_config)
628                 .setOnClickListener(this::onRemoveStatsAndConnectivityConfigBtnClick);
629         view.findViewById(R.id.get_stats_and_connectivity_report)
630                 .setOnClickListener(this::onGetStatsAndConnectivityReportBtnClick);
631         /** Driving sessions section */
632         view.findViewById(R.id.send_driving_sessions_config)
633                 .setOnClickListener(this::onSendDrivingSessionsConfigBtnClick);
634         view.findViewById(R.id.download_data)
635                 .setOnClickListener(this::onDownloadDataBtnClick);
636         view.findViewById(R.id.emulate_suspend_to_RAM)
637                 .setOnClickListener(this::onEmulateSuspendToRAMBtnClick);
638         view.findViewById(R.id.emulate_reboot)
639                 .setOnClickListener(this::onEmulateRebootBtnClick);
640         view.findViewById(R.id.remove_driving_sessions_config)
641                 .setOnClickListener(this::onRemoveDrivingSessionsConfigBtnClick);
642         view.findViewById(R.id.get_driving_sessions_report)
643                 .setOnClickListener(this::onGetDrivingSessionsReportBtnClick);
644         /** MemoryPublisher section */
645         view.findViewById(R.id.send_memory_config)
646                 .setOnClickListener(this::onSendMemoryConfigBtnClick);
647         view.findViewById(R.id.remove_memory_config)
648                 .setOnClickListener(this::onRemoveMemoryConfigBtnClick);
649         view.findViewById(R.id.get_memory_report)
650                 .setOnClickListener(this::onGetMemoryReportBtnClick);
651         /** StatsPublisher process_memory_snapshot */
652         view.findViewById(R.id.send_on_process_memory_snapshot_config)
653                 .setOnClickListener(this::onSendProcessMemorySnapshotConfigBtnClick);
654         view.findViewById(R.id.remove_on_process_memory_snapshot_config)
655                 .setOnClickListener(this::onRemoveProcessMemorySnapshotConfigBtnClick);
656         view.findViewById(R.id.get_on_process_memory_snapshot_report)
657                 .setOnClickListener(this::onGetProcessMemorySnapshotReportBtnClick);
658         /** StatsPublisher process_start_time */
659         view.findViewById(R.id.send_on_process_start_time_config)
660                 .setOnClickListener(this::onSendProcessStartTimeConfigBtnClick);
661         view.findViewById(R.id.remove_on_process_start_time_config)
662                 .setOnClickListener(this::onRemoveProcessStartTimeConfigBtnClick);
663         view.findViewById(R.id.get_on_process_start_time_report)
664                 .setOnClickListener(this::onGetProcessStartTimeReportBtnClick);
665         /** Print mem info button */
666         view.findViewById(R.id.print_mem_info_btn).setOnClickListener(this::onPrintMemInfoBtnClick);
667         return view;
668     }
669 
showOutput(String s)670     private void showOutput(String s) {
671         String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS"));
672         String text = now + " : " + s;
673         Log.i(TAG, text);
674         mActivity.runOnUiThread(
675                 () -> {
676                     mOutputTextView.setText(text + "\n" + mOutputTextView.getText());
677                 });
678     }
679 
toggleMetricsConfigButtons(View view)680     private void toggleMetricsConfigButtons(View view) {
681         boolean visible = mConfigButtonsView.getVisibility() == View.VISIBLE;
682         mConfigButtonsView.setVisibility(visible ? View.GONE : View.VISIBLE);
683         mTootleConfigsBtn.setText(visible ? "Configs ▶" : "Configs ▼");
684     }
685 
enableReportNotification(View view)686     private void enableReportNotification(View view) {
687         mReceiveReportNotification = !mReceiveReportNotification;
688         mEnableReportNotificationButton.setText(
689                 getString(R.string.receive_report_notification_text, mReceiveReportNotification));
690         if (mReceiveReportNotification) {
691             mCarTelemetryManager.setReportReadyListener(mExecutor, this::onReportReady);
692         } else {
693             mCarTelemetryManager.clearReportReadyListener();
694         }
695     }
696 
697     /** Implementation of functional interface {@link CarTelemetryManager.ReportReadyListener}. */
onReportReady(@onNull String metricsConfigName)698     private void onReportReady(@NonNull String metricsConfigName) {
699         String s = "Report for MetricsConfig " + metricsConfigName + " is ready.";
700         showOutput(s);
701     }
702 
onSendGearChangeConfigBtnClick(View view)703     private void onSendGearChangeConfigBtnClick(View view) {
704         mCarTelemetryManager.addMetricsConfig(
705                 ON_GEAR_CHANGE_CONFIG_NAME,
706                 METRICS_CONFIG_ON_GEAR_CHANGE_V1.toByteArray(),
707                 mExecutor,
708                 mAddMetricsConfigCallback);
709     }
710 
onRemoveGearChangeConfigBtnClick(View view)711     private void onRemoveGearChangeConfigBtnClick(View view) {
712         showOutput("Removing MetricsConfig that listens for gear change...");
713         mCarTelemetryManager.removeMetricsConfig(ON_GEAR_CHANGE_CONFIG_NAME);
714     }
715 
onGetGearChangeReportBtnClick(View view)716     private void onGetGearChangeReportBtnClick(View view) {
717         mCarTelemetryManager.getFinishedReport(ON_GEAR_CHANGE_CONFIG_NAME, mExecutor, mListener);
718     }
719 
onSendProcessMemoryConfigBtnClick(View view)720     private void onSendProcessMemoryConfigBtnClick(View view) {
721         mCarTelemetryManager.addMetricsConfig(
722                 PROCESS_MEMORY_CONFIG_NAME,
723                 METRICS_CONFIG_PROCESS_MEMORY_V1.toByteArray(),
724                 mExecutor,
725                 mAddMetricsConfigCallback);
726     }
727 
onRemoveProcessMemoryConfigBtnClick(View view)728     private void onRemoveProcessMemoryConfigBtnClick(View view) {
729         showOutput("Removing MetricsConfig that listens for PROCESS_MEMORY_STATE...");
730         mCarTelemetryManager.removeMetricsConfig(PROCESS_MEMORY_CONFIG_NAME);
731     }
732 
onGetProcessMemoryReportBtnClick(View view)733     private void onGetProcessMemoryReportBtnClick(View view) {
734         mCarTelemetryManager.getFinishedReport(PROCESS_MEMORY_CONFIG_NAME, mExecutor, mListener);
735     }
736 
onSendAppStartMemoryStateCapturedConfigBtnClick(View view)737     private void onSendAppStartMemoryStateCapturedConfigBtnClick(View view) {
738         mCarTelemetryManager.addMetricsConfig(
739                 APP_START_MEMORY_STATE_CAPTURED_CONFIG_NAME,
740                 METRICS_CONFIG_APP_START_MEMORY_V1.toByteArray(),
741                 mExecutor,
742                 mAddMetricsConfigCallback);
743     }
744 
onRemoveAppStartMemoryStateCapturedConfigBtnClick(View view)745     private void onRemoveAppStartMemoryStateCapturedConfigBtnClick(View view) {
746         showOutput("Removing MetricsConfig that listens for APP_START_MEMORY_STATE_CAPTURED...");
747         mCarTelemetryManager.removeMetricsConfig(APP_START_MEMORY_STATE_CAPTURED_CONFIG_NAME);
748     }
749 
onGetAppStartMemoryStateCapturedReportBtnClick(View view)750     private void onGetAppStartMemoryStateCapturedReportBtnClick(View view) {
751         mCarTelemetryManager.getFinishedReport(
752                 APP_START_MEMORY_STATE_CAPTURED_CONFIG_NAME, mExecutor, mListener);
753     }
754 
onSendActivityForegroundStateChangedConfigBtnClick(View view)755     private void onSendActivityForegroundStateChangedConfigBtnClick(View view) {
756         mCarTelemetryManager.addMetricsConfig(
757                 ACTIVITY_FOREGROUND_STATE_CHANGED_CONFIG_NAME,
758                 METRICS_CONFIG_ACTIVITY_FOREGROUND_STATE_V1.toByteArray(),
759                 mExecutor,
760                 mAddMetricsConfigCallback);
761     }
762 
onRemoveActivityForegroundStateChangedConfigBtnClick(View view)763     private void onRemoveActivityForegroundStateChangedConfigBtnClick(View view) {
764         showOutput("Removing MetricsConfig that listens for ACTIVITY_FOREGROUND_STATE_CHANGED...");
765         mCarTelemetryManager.removeMetricsConfig(ACTIVITY_FOREGROUND_STATE_CHANGED_CONFIG_NAME);
766     }
767 
onGetActivityForegroundStateChangedReportBtnClick(View view)768     private void onGetActivityForegroundStateChangedReportBtnClick(View view) {
769         mCarTelemetryManager.getFinishedReport(
770                 ACTIVITY_FOREGROUND_STATE_CHANGED_CONFIG_NAME, mExecutor, mListener);
771     }
772 
onSendProcessCpuTimeConfigBtnClick(View view)773     private void onSendProcessCpuTimeConfigBtnClick(View view) {
774         mCarTelemetryManager.addMetricsConfig(
775                 PROCESS_CPU_TIME_CONFIG_NAME,
776                 METRICS_CONFIG_PROCESS_CPU_TIME_V1.toByteArray(),
777                 mExecutor,
778                 mAddMetricsConfigCallback);
779     }
780 
onRemoveProcessCpuTimeConfigBtnClick(View view)781     private void onRemoveProcessCpuTimeConfigBtnClick(View view) {
782         showOutput("Removing MetricsConfig that listens for PROCESS_CPU_TIME...");
783         mCarTelemetryManager.removeMetricsConfig(PROCESS_CPU_TIME_CONFIG_NAME);
784     }
785 
onGetProcessCpuTimeReportBtnClick(View view)786     private void onGetProcessCpuTimeReportBtnClick(View view) {
787         mCarTelemetryManager.getFinishedReport(PROCESS_CPU_TIME_CONFIG_NAME, mExecutor, mListener);
788     }
789 
onSendAppCrashOccurredConfigBtnClick(View view)790     private void onSendAppCrashOccurredConfigBtnClick(View view) {
791         mCarTelemetryManager.addMetricsConfig(
792                 APP_CRASH_OCCURRED_CONFIG_NAME,
793                 METRICS_CONFIG_APP_CRASH_OCCURRED_V1.toByteArray(),
794                 mExecutor,
795                 mAddMetricsConfigCallback);
796     }
797 
onRemoveAppCrashOccurredConfigBtnClick(View view)798     private void onRemoveAppCrashOccurredConfigBtnClick(View view) {
799         showOutput("Removing MetricsConfig that listens for APP_CRASH_OCCURRED...");
800         mCarTelemetryManager.removeMetricsConfig(APP_CRASH_OCCURRED_CONFIG_NAME);
801     }
802 
onGetAppCrashOccurredReportBtnClick(View view)803     private void onGetAppCrashOccurredReportBtnClick(View view) {
804         mCarTelemetryManager.getFinishedReport(
805                 APP_CRASH_OCCURRED_CONFIG_NAME, mExecutor, mListener);
806     }
807 
onSendAnrOccurredConfigBtnClick(View view)808     private void onSendAnrOccurredConfigBtnClick(View view) {
809         mCarTelemetryManager.addMetricsConfig(
810                 ANR_OCCURRED_CONFIG_NAME,
811                 METRICS_CONFIG_ANR_OCCURRED_V1.toByteArray(),
812                 mExecutor,
813                 mAddMetricsConfigCallback);
814     }
815 
onRemoveAnrOccurredConfigBtnClick(View view)816     private void onRemoveAnrOccurredConfigBtnClick(View view) {
817         showOutput("Removing MetricsConfig that listens for ANR_OCCURRED...");
818         mCarTelemetryManager.removeMetricsConfig(ANR_OCCURRED_CONFIG_NAME);
819     }
820 
onGetAnrOccurredReportBtnClick(View view)821     private void onGetAnrOccurredReportBtnClick(View view) {
822         mCarTelemetryManager.getFinishedReport(ANR_OCCURRED_CONFIG_NAME, mExecutor, mListener);
823     }
824 
onSendWtfOccurredConfigBtnClick(View view)825     private void onSendWtfOccurredConfigBtnClick(View view) {
826         mCarTelemetryManager.addMetricsConfig(
827                 WTF_OCCURRED_CONFIG_NAME,
828                 METRICS_CONFIG_WTF_OCCURRED_V1.toByteArray(),
829                 mExecutor,
830                 mAddMetricsConfigCallback);
831     }
832 
onRemoveWtfOccurredConfigBtnClick(View view)833     private void onRemoveWtfOccurredConfigBtnClick(View view) {
834         showOutput("Removing MetricsConfig that listens for WTF_OCCURRED...");
835         mCarTelemetryManager.removeMetricsConfig(WTF_OCCURRED_CONFIG_NAME);
836     }
837 
onGetWtfOccurredReportBtnClick(View view)838     private void onGetWtfOccurredReportBtnClick(View view) {
839         mCarTelemetryManager.getFinishedReport(WTF_OCCURRED_CONFIG_NAME, mExecutor, mListener);
840     }
841 
onSendWifiNetstatsConfigBtnClick(View view)842     private void onSendWifiNetstatsConfigBtnClick(View view) {
843         showOutput("If the config is added successfully, it will produce a report on the top "
844                 + "3 wifi network traffic consumers after 1 driving sessions.");
845         mCarTelemetryManager.addMetricsConfig(
846                 WIFI_TOP_CONSUMERS_CONFIG_NAME,
847                 METRICS_CONFIG_WIFI_TOP_CONSUMERS
848                         .toBuilder()
849                         .setScript(
850                                 readTelemetryScript(R.raw.telemetry_stats_and_connectivity_script))
851                         .build()
852                         .toByteArray(),
853                 mExecutor,
854                 mAddMetricsConfigCallback);
855     }
856 
onRemoveWifiNetstatsConfigBtnClick(View view)857     private void onRemoveWifiNetstatsConfigBtnClick(View view) {
858         showOutput("Removing MetricsConfig on wifi netstats top consumers...");
859         mCarTelemetryManager.removeMetricsConfig(WIFI_TOP_CONSUMERS_CONFIG_NAME);
860     }
861 
onGetWifiNetstatsReportBtnClick(View view)862     private void onGetWifiNetstatsReportBtnClick(View view) {
863         mCarTelemetryManager.getFinishedReport(
864                 WIFI_TOP_CONSUMERS_CONFIG_NAME, mExecutor, mListener);
865     }
866 
onSendStatsAndConnectivityConfigBtnClick(View view)867     private void onSendStatsAndConnectivityConfigBtnClick(View view) {
868         String luaScript = readTelemetryScript(R.raw.telemetry_stats_and_connectivity_script);
869         showOutput(
870                 "If the config added successfully, emulate power state change by first running:\n"
871                         + "$ adb shell cmd car_service suspend\n"
872                         + "and, after 1 minute pause:\n"
873                         + "$ adb shell cmd car_service resume\n"
874                         + "Repeat this 3 times and then pull the report after 10 minutes.");
875         TelemetryProto.MetricsConfig config =
876                 METRICS_CONFIG_STATS_AND_CONNECTIVITY_V1.toBuilder().setScript(luaScript).build();
877         mCarTelemetryManager.addMetricsConfig(
878                 STATS_AND_CONNECTIVITY_CONFIG_NAME,
879                 config.toByteArray(),
880                 mExecutor,
881                 mAddMetricsConfigCallback);
882     }
883 
readTelemetryScript(@awRes int fileResourceId)884     private String readTelemetryScript(@RawRes int fileResourceId) {
885         try (InputStream is =
886                      getResources().openRawResource(fileResourceId)) {
887             byte[] bytes = new byte[is.available()];
888             is.read(bytes);
889             return new String(bytes);
890         } catch (IOException e) {
891             throw new RuntimeException(
892                     "Unable to send MetricsConfig, because reading Lua script from file failed.",
893                     e);
894         }
895     }
896 
onRemoveStatsAndConnectivityConfigBtnClick(View view)897     private void onRemoveStatsAndConnectivityConfigBtnClick(View view) {
898         showOutput("Removing MetricsConfig that listens for stats data & connectivity data...");
899         mCarTelemetryManager.removeMetricsConfig(STATS_AND_CONNECTIVITY_CONFIG_NAME);
900     }
901 
onGetStatsAndConnectivityReportBtnClick(View view)902     private void onGetStatsAndConnectivityReportBtnClick(View view) {
903         mCarTelemetryManager.getFinishedReport(
904                 STATS_AND_CONNECTIVITY_CONFIG_NAME, mExecutor, mListener);
905     }
906 
onSendDrivingSessionsConfigBtnClick(View view)907     private void onSendDrivingSessionsConfigBtnClick(View view) {
908         String luaScript = readTelemetryScript(R.raw.telemetry_driving_sessions_script);
909         showOutput(
910                 "If the config added successfully, please induce three driving sessions\n"
911                         + "by using both Suspend-to-RAM and Reboot buttons and then check "
912                         + "generated report\n"
913                         + "Suggested sequence: \n"
914                         + "1) Load new script\n"
915                         + "2) Click DOWNLOAD DATA button and note the size of the file downloaded"
916                         + ".\n"
917                         + "3) Click on SUSPEND TO RAM to complete the 1st driving session. The "
918                         + "app should reappear after a brief break.\n"
919                         + "4) Click DOWNLOAD DATA to download the same file the 2nd time.\n"
920                         + "5) Click on REBOOT button to complete the 2nd driving session and test"
921                         + " preserving of session data on disk at shutdown.\n"
922                         + "6) After the reboot is complete, bring up the Kitchensink app and "
923                         + "telemetry screen again to continue the test.\n"
924                         + "7) Click DOWNLOAD DATA to download the same file the 3rd time.\n"
925                         + "8) Click on SUSPEND TO RAM to complete the 3rd driving session.\n"
926                         + "9) After the screen and the app are brought back up, click on GET "
927                         + "REPORT.\n"
928                         + "10) The report requires 3 driving sessions to be generated.\n"
929                         + "11) In the report, there will be three separate entries that show "
930                         + "total traffic for kitchen sink app.\n"
931                         + "12) Each entry corresponds to a driving session.\n"
932                         + "13) Each entry should show the number of bytes transferred at least "
933                         + "equal to the size of the file downloaded each of the 3 times.\n"
934         );
935         TelemetryProto.MetricsConfig config =
936                 METRICS_CONFIG_DRIVING_SESSIONS.toBuilder().setScript(luaScript).build();
937         mCarTelemetryManager.addMetricsConfig(
938                 WIFI_STATS_DRIVING_SESSIONS_CONFIG_NAME,
939                 config.toByteArray(),
940                 mExecutor,
941                 mAddMetricsConfigCallback);
942     }
943 
onDownloadDataBtnClick(View view)944     private void onDownloadDataBtnClick(View view) {
945         showOutput("Downloading data using curl...");
946 
947         // First, create a directory where the file will be downloaded.
948         File tempDirectory;
949         try {
950             tempDirectory = Files.createTempDirectory(mActivity.getFilesDir().toPath(),
951                     "downloadDir").toFile();
952         } catch (IOException e) {
953             showOutput(e.toString());
954             return;
955         }
956 
957         boolean status = runCommand(tempDirectory, "curl", "-O", "-L",
958                 "https://yts.devicecertification.youtube/yts_server.zip");
959         Path filePath = Paths.get(tempDirectory.getAbsolutePath(), "yts_server.zip");
960         if (status && Files.exists(filePath)) {
961             try {
962                 showOutput("Successfully downloaded a file with size " + Files.size(filePath)
963                         + " bytes.");
964             } catch (IOException e) {
965                 showOutput(
966                         "Successfully downloaded a file but exception occurred: " + e.toString());
967             }
968         }
969 
970         // clean up by removing the temporary download directory with all its contents.
971         tempDirectory.delete();
972     }
973 
runCommand(@ullable File currentDirectory, String... command)974     private boolean runCommand(@Nullable File currentDirectory, String... command) {
975         Process p = null;
976         BufferedReader is = null;
977         StringBuilder out = new StringBuilder();
978         boolean success = false;
979         try {
980             ProcessBuilder processBuilder = new ProcessBuilder(command);
981             processBuilder.redirectErrorStream(true);
982             if (currentDirectory != null) {
983                 processBuilder.directory(currentDirectory);
984             }
985             p = processBuilder.start();
986             is = new BufferedReader(new InputStreamReader(p.getInputStream()));
987             String line;
988 
989             while ((line = is.readLine()) != null) {
990                 out.append(line);
991                 out.append(System.lineSeparator());
992             }
993             p.waitFor();
994         } catch (Exception e) {
995             showOutput(e.toString());
996         } finally {
997             if (p != null) {
998                 p.destroy();
999             }
1000             if (is != null) {
1001                 try {
1002                     is.close();
1003                 } catch (IOException e) {
1004                     // ignore
1005                 }
1006             }
1007         }
1008         if (p != null) {
1009             int processExitValue = p.exitValue();
1010             if (processExitValue == 0) {
1011                 showOutput(out.toString().trim());
1012                 success = true;
1013             }
1014         }
1015         return success;
1016     }
1017 
onEmulateSuspendToRAMBtnClick(View view)1018     private void onEmulateSuspendToRAMBtnClick(View view) {
1019         runCommand(null, "cmd", "car_service", "suspend", "--simulate", "--wakeup-after", "3");
1020     }
1021 
onEmulateRebootBtnClick(View view)1022     private void onEmulateRebootBtnClick(View view) {
1023         runCommand(null, "cmd", "car_service", "power-off", "--reboot");
1024     }
1025 
onRemoveDrivingSessionsConfigBtnClick(View view)1026     private void onRemoveDrivingSessionsConfigBtnClick(View view) {
1027         showOutput("Removing MetricsConfig that listens for driving sessions...");
1028         mCarTelemetryManager.removeMetricsConfig(WIFI_STATS_DRIVING_SESSIONS_CONFIG_NAME);
1029     }
1030 
onGetDrivingSessionsReportBtnClick(View view)1031     private void onGetDrivingSessionsReportBtnClick(View view) {
1032         mCarTelemetryManager.getFinishedReport(
1033                 WIFI_STATS_DRIVING_SESSIONS_CONFIG_NAME, mExecutor, mListener);
1034     }
1035 
onSendMemoryConfigBtnClick(View view)1036     private void onSendMemoryConfigBtnClick(View view) {
1037         showOutput("If the MetricsConfig is added successfully, it will produce 3 metrics "
1038                 + "reports on available memory. The reports are produced 3 seconds apart. "
1039                 + "After 3 reports, the MetricsConfig's lifecycle is considered finished.");
1040         mCarTelemetryManager.addMetricsConfig(
1041                 MEMORY_CONFIG_NAME,
1042                 METRICS_CONFIG_MEMORY_V1.toByteArray(),
1043                 mExecutor,
1044                 mAddMetricsConfigCallback);
1045     }
1046 
onRemoveMemoryConfigBtnClick(View view)1047     private void onRemoveMemoryConfigBtnClick(View view) {
1048         showOutput("Removing MetricsConfig for memory...");
1049         mCarTelemetryManager.removeMetricsConfig(MEMORY_CONFIG_NAME);
1050     }
1051 
onGetMemoryReportBtnClick(View view)1052     private void onGetMemoryReportBtnClick(View view) {
1053         mCarTelemetryManager.getFinishedReport(MEMORY_CONFIG_NAME, mExecutor, mListener);
1054     }
1055 
onSendProcessMemorySnapshotConfigBtnClick(View view)1056     private void onSendProcessMemorySnapshotConfigBtnClick(View view) {
1057         mCarTelemetryManager.addMetricsConfig(
1058                 PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME,
1059                 METRICS_CONFIG_PROCESS_MEMORY_SNAPSHOT_V1.toByteArray(),
1060                 mExecutor,
1061                 mAddMetricsConfigCallback);
1062     }
1063 
onRemoveProcessMemorySnapshotConfigBtnClick(View view)1064     private void onRemoveProcessMemorySnapshotConfigBtnClick(View view) {
1065         showOutput("Removing MetricsConfig that listens for PROCESS_MEMORY_SNAPSHOT...");
1066         mCarTelemetryManager.removeMetricsConfig(PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME);
1067     }
1068 
onGetProcessMemorySnapshotReportBtnClick(View view)1069     private void onGetProcessMemorySnapshotReportBtnClick(View view) {
1070         mCarTelemetryManager.getFinishedReport(
1071                 PROCESS_MEMORY_SNAPSHOT_CONFIG_NAME, mExecutor, mListener);
1072     }
1073 
onSendProcessStartTimeConfigBtnClick(View view)1074     private void onSendProcessStartTimeConfigBtnClick(View view) {
1075         mCarTelemetryManager.addMetricsConfig(
1076                 PROCESS_START_TIME_CONFIG_NAME,
1077                 METRICS_CONFIG_PROCESS_START_TIME_V1.toByteArray(),
1078                 mExecutor,
1079                 mAddMetricsConfigCallback);
1080     }
1081 
onRemoveProcessStartTimeConfigBtnClick(View view)1082     private void onRemoveProcessStartTimeConfigBtnClick(View view) {
1083         showOutput("Removing MetricsConfig that listens for PROCESS_START_TIME...");
1084         mCarTelemetryManager.removeMetricsConfig(PROCESS_START_TIME_CONFIG_NAME);
1085     }
1086 
onGetProcessStartTimeReportBtnClick(View view)1087     private void onGetProcessStartTimeReportBtnClick(View view) {
1088         mCarTelemetryManager.getFinishedReport(
1089                 PROCESS_START_TIME_CONFIG_NAME, mExecutor, mListener);
1090     }
1091 
1092     /** Gets a MemoryInfo object for the device's current memory status. */
getAvailableMemory()1093     private ActivityManager.MemoryInfo getAvailableMemory() {
1094         ActivityManager activityManager = getActivity().getSystemService(ActivityManager.class);
1095         ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
1096         activityManager.getMemoryInfo(memoryInfo);
1097         return memoryInfo;
1098     }
1099 
onPrintMemInfoBtnClick(View view)1100     private void onPrintMemInfoBtnClick(View view) {
1101         // Use android's "alloc-stress" system tool to create an artificial memory pressure.
1102         ActivityManager.MemoryInfo info = getAvailableMemory();
1103         showOutput("MemoryInfo availMem=" + (info.availMem / 1024 / 1024) + "/"
1104                 + (info.totalMem / 1024 / 1024) + "mb, isLowMem=" + info.lowMemory
1105                 + ", threshold=" + (info.threshold / 1024 / 1024) + "mb");
1106     }
1107 
1108     /**
1109      * Updates the view to show {@link CarTelemetryManager#addMetricsConfig(String, byte[],
1110      * Executor, CarTelemetryManager.AddMetricsConfigCallback)} status code. The callbacks are
1111      * executed in {@link #mExecutor}.
1112      */
1113     private final class AddMetricsConfigCallbackImpl
1114             implements CarTelemetryManager.AddMetricsConfigCallback {
1115 
1116         @Override
onAddMetricsConfigStatus(@onNull String metricsConfigName, int statusCode)1117         public void onAddMetricsConfigStatus(@NonNull String metricsConfigName, int statusCode) {
1118             showOutput("Add MetricsConfig status for " + metricsConfigName + ": "
1119                     + statusCodeToString(statusCode));
1120         }
1121 
statusCodeToString(int statusCode)1122         private String statusCodeToString(int statusCode) {
1123             switch (statusCode) {
1124                 case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SUCCEEDED:
1125                     return "SUCCESS";
1126                 case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_ALREADY_EXISTS:
1127                     return "ERROR ALREADY_EXISTS";
1128                 case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_VERSION_TOO_OLD:
1129                     return "ERROR VERSION_TOO_OLD";
1130                 case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_PARSE_FAILED:
1131                     return "ERROR PARSE_FAILED";
1132                 case CarTelemetryManager.STATUS_ADD_METRICS_CONFIG_SIGNATURE_VERIFICATION_FAILED:
1133                     return "ERROR SIGNATURE_VERIFICATION_FAILED";
1134                 default:
1135                     return "ERROR UNKNOWN";
1136             }
1137         }
1138     }
1139 
1140     /**
1141      * Implementation of the {@link CarTelemetryManager.MetricsReportCallback}. They update the view
1142      * to show the outputs from the APIs of {@link CarTelemetryManager}. The callbacks are executed
1143      * in {@link mExecutor}.
1144      */
1145     private final class FinishedReportListenerImpl implements
1146             CarTelemetryManager.MetricsReportCallback {
1147 
1148         @Override
onResult( @onNull String metricsConfigName, @Nullable PersistableBundle report, @Nullable byte[] telemetryError, @CarTelemetryManager.MetricsReportStatus int status)1149         public void onResult(
1150                 @NonNull String metricsConfigName,
1151                 @Nullable PersistableBundle report,
1152                 @Nullable byte[] telemetryError,
1153                 @CarTelemetryManager.MetricsReportStatus int status) {
1154             if (report != null) {
1155                 report.size(); // unparcel()'s
1156                 showOutput(metricsConfigName + " has status: "
1157                         + statusCodeToString(status) + ". Printing report: \n\t" + report);
1158             } else if (telemetryError != null) {
1159                 parseError(metricsConfigName, telemetryError);
1160             } else {
1161                 showOutput("No report exists for MetricsConfig " + metricsConfigName
1162                         + ", reason = " + statusCodeToString(status));
1163             }
1164         }
1165 
parseError(@onNull String metricsConfigName, @NonNull byte[] error)1166         private void parseError(@NonNull String metricsConfigName, @NonNull byte[] error) {
1167             try {
1168                 TelemetryProto.TelemetryError telemetryError =
1169                         TelemetryProto.TelemetryError.parseFrom(error);
1170                 showOutput("Error for " + metricsConfigName + ": " + telemetryError);
1171             } catch (InvalidProtocolBufferException e) {
1172                 showOutput("Unable to parse error result for MetricsConfig " + metricsConfigName
1173                         + ": " + e.getMessage());
1174             }
1175         }
1176 
statusCodeToString(int statusCode)1177         private String statusCodeToString(int statusCode) {
1178             switch (statusCode) {
1179                 case CarTelemetryManager.STATUS_GET_METRICS_CONFIG_FINISHED:
1180                     return "REPORT RETRIEVED";
1181                 case CarTelemetryManager.STATUS_GET_METRICS_CONFIG_PENDING:
1182                     return "REPORT PENDING";
1183                 case CarTelemetryManager.STATUS_GET_METRICS_CONFIG_INTERIM_RESULTS:
1184                     return "INTERIM RESULT EXISTS";
1185                 case CarTelemetryManager.STATUS_GET_METRICS_CONFIG_RUNTIME_ERROR:
1186                     return "RUNTIME ERROR";
1187                 case CarTelemetryManager.STATUS_GET_METRICS_CONFIG_DOES_NOT_EXIST:
1188                     return "METRICS CONFIG DOES NOT EXIST";
1189                 default:
1190                     return "INVALID STATUS CODE";
1191             }
1192         }
1193     }
1194 }
1195