blob: 5a76abc9543cb5ac4adb7c9d018dd2e3277cb1da [file] [log] [blame]
/*
* Copyright (C) 2021 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.
*/
package com.google.android.car.kitchensink.telemetry;
import static com.android.car.telemetry.TelemetryProto.StatsPublisher.SystemMetric.PROCESS_MEMORY_STATE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.car.telemetry.CarTelemetryManager;
import android.car.telemetry.MetricsConfigKey;
import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.android.car.telemetry.TelemetryProto;
import com.google.android.car.kitchensink.KitchenSinkActivity;
import com.google.android.car.kitchensink.R;
import com.google.protobuf.InvalidProtocolBufferException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class CarTelemetryTestFragment extends Fragment {
/** Hello World test from vehicle property publisher by injecting gear change. */
private static final String LUA_SCRIPT_ON_GEAR_CHANGE =
"function onGearChange(published_data, state)\n"
+ " result = {data = \"Hello World!\"}\n"
+ " on_script_finished(result)\n"
+ "end\n";
private static final TelemetryProto.Publisher VEHICLE_PROPERTY_PUBLISHER =
TelemetryProto.Publisher.newBuilder()
.setVehicleProperty(
TelemetryProto.VehiclePropertyPublisher.newBuilder()
.setVehiclePropertyId(VehicleProperty.GEAR_SELECTION)
.setReadRate(0f)
.build()
).build();
private static final TelemetryProto.MetricsConfig METRICS_CONFIG_ON_GEAR_CHANGE_V1 =
TelemetryProto.MetricsConfig.newBuilder()
.setName("my_metrics_config")
.setVersion(1)
.setScript(LUA_SCRIPT_ON_GEAR_CHANGE)
.addSubscribers(
TelemetryProto.Subscriber.newBuilder()
.setHandler("onGearChange")
.setPublisher(VEHICLE_PROPERTY_PUBLISHER)
.setPriority(100)) // low priority
.build();
private static final MetricsConfigKey ON_GEAR_CHANGE_KEY_V1 = new MetricsConfigKey(
METRICS_CONFIG_ON_GEAR_CHANGE_V1.getName(),
METRICS_CONFIG_ON_GEAR_CHANGE_V1.getVersion());
/** Memory metrics test. */
private static final String LUA_SCRIPT_ON_PROCESS_MEMORY_STATE = new StringBuilder()
.append("function calculateAverage(tbl)\n")
.append(" sum = 0\n")
.append(" size = 0\n")
.append(" for _, value in ipairs(tbl) do\n")
.append(" sum = sum + value\n")
.append(" size = size + 1\n")
.append(" end\n")
.append(" return sum/size\n")
.append("end\n")
.append("function onProcessMemory(published_data, state)\n")
.append(" result = {}\n")
.append(" result.page_fault_avg = calculateAverage(published_data.page_fault)\n")
.append(" result.major_page_fault_avg = calculateAverage("
+ "published_data.page_major_fault)\n")
.append(" result.oom_adj_score_avg = calculateAverage("
+ "published_data.oom_adj_score)\n")
.append(" result.rss_in_bytes_avg = calculateAverage(published_data.rss_in_bytes)\n")
.append(" result.swap_in_bytes_avg = calculateAverage("
+ "published_data.swap_in_bytes)\n")
.append(" result.cache_in_bytes_avg = calculateAverage("
+ "published_data.cache_in_bytes)\n")
.append(" on_script_finished(result)\n")
.append("end\n")
.toString();
private static final TelemetryProto.Publisher PROCESS_MEMORY_PUBLISHER =
TelemetryProto.Publisher.newBuilder()
.setStats(
TelemetryProto.StatsPublisher.newBuilder()
.setSystemMetric(PROCESS_MEMORY_STATE)
).build();
private static final TelemetryProto.MetricsConfig METRICS_CONFIG_PROCESS_MEMORY_V1 =
TelemetryProto.MetricsConfig.newBuilder()
.setName("process_memory_metrics_config")
.setVersion(1)
.setScript(LUA_SCRIPT_ON_PROCESS_MEMORY_STATE)
.addSubscribers(
TelemetryProto.Subscriber.newBuilder()
.setHandler("onProcessMemory")
.setPublisher(PROCESS_MEMORY_PUBLISHER)
.setPriority(0)) // high priority
.build();
private static final MetricsConfigKey PROCESS_MEMORY_KEY_V1 = new MetricsConfigKey(
METRICS_CONFIG_PROCESS_MEMORY_V1.getName(),
METRICS_CONFIG_PROCESS_MEMORY_V1.getVersion());
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private CarTelemetryManager mCarTelemetryManager;
private CarTelemetryResultsListenerImpl mListener;
private KitchenSinkActivity mActivity;
private TextView mOutputTextView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
mActivity = (KitchenSinkActivity) getActivity();
mCarTelemetryManager = mActivity.getCarTelemetryManager();
mListener = new CarTelemetryResultsListenerImpl();
mCarTelemetryManager.setListener(mExecutor, mListener);
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.car_telemetry_test, container, false);
mOutputTextView = view.findViewById(R.id.output_textview);
Button sendGearConfigBtn = view.findViewById(R.id.send_on_gear_change_config);
Button getGearReportBtn = view.findViewById(R.id.get_on_gear_change_report);
Button removeGearConfigBtn = view.findViewById(R.id.remove_on_gear_change_config);
sendGearConfigBtn.setOnClickListener(this::onSendGearChangeConfigBtnClick);
removeGearConfigBtn.setOnClickListener(this::onRemoveGearChangeConfigBtnClick);
getGearReportBtn.setOnClickListener(this::onGetGearChangeReportBtnClick);
mOutputTextView = view.findViewById(R.id.output_textview);
Button sendProcessMemConfigBtn = view.findViewById(R.id.send_on_process_memory_config);
Button getProcessMemReportBtn = view.findViewById(R.id.get_on_process_memory_report);
Button removeProcessMemConfigBtn = view.findViewById(R.id.remove_on_process_memory_config);
sendProcessMemConfigBtn.setOnClickListener(this::onSendProcessMemoryConfigBtnClick);
removeProcessMemConfigBtn.setOnClickListener(this::onRemoveProcessMemoryConfigBtnClick);
getProcessMemReportBtn.setOnClickListener(this::onGetProcessMemoryReportBtnClick);
return view;
}
private void showOutput(String s) {
mActivity.runOnUiThread(() -> mOutputTextView.setText(s));
}
private void onSendGearChangeConfigBtnClick(View view) {
showOutput("Sending MetricsConfig that listen for gear change...");
mCarTelemetryManager.addMetricsConfig(ON_GEAR_CHANGE_KEY_V1,
METRICS_CONFIG_ON_GEAR_CHANGE_V1.toByteArray());
}
private void onRemoveGearChangeConfigBtnClick(View view) {
showOutput("Removing MetricsConfig that listens for gear change...");
mCarTelemetryManager.removeMetricsConfig(ON_GEAR_CHANGE_KEY_V1);
}
private void onGetGearChangeReportBtnClick(View view) {
showOutput("Fetching report... If nothing shows up after a few seconds, "
+ "then no result exists");
mCarTelemetryManager.sendFinishedReports(ON_GEAR_CHANGE_KEY_V1);
}
private void onSendProcessMemoryConfigBtnClick(View view) {
showOutput("Sending MetricsConfig that listen for process memory state...");
mCarTelemetryManager.addMetricsConfig(PROCESS_MEMORY_KEY_V1,
METRICS_CONFIG_PROCESS_MEMORY_V1.toByteArray());
}
private void onRemoveProcessMemoryConfigBtnClick(View view) {
showOutput("Removing MetricsConfig that listens for process memory state...");
mCarTelemetryManager.removeMetricsConfig(PROCESS_MEMORY_KEY_V1);
}
private void onGetProcessMemoryReportBtnClick(View view) {
showOutput("Fetching report for process memory state... If nothing shows up after "
+ "a few seconds, then no result exists");
mCarTelemetryManager.sendFinishedReports(PROCESS_MEMORY_KEY_V1);
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
/**
* Implementation of the {@link CarTelemetryManager.CarTelemetryResultsListener}. They update
* the view to show the outputs from the APIs of {@link CarTelemetryManager}.
* The callbacks are executed in {@link mExecutor}.
*/
private final class CarTelemetryResultsListenerImpl
implements CarTelemetryManager.CarTelemetryResultsListener {
@Override
public void onResult(@NonNull MetricsConfigKey key, @NonNull byte[] result) {
PersistableBundle bundle;
try (ByteArrayInputStream bis = new ByteArrayInputStream(result)) {
bundle = PersistableBundle.readFromStream(bis);
} catch (IOException e) {
bundle = null;
}
showOutput("Result is " + bundle.toString());
}
@Override
public void onError(@NonNull MetricsConfigKey key, @NonNull byte[] error) {
try {
TelemetryProto.TelemetryError telemetryError =
TelemetryProto.TelemetryError.parseFrom(error);
showOutput("Error is " + telemetryError);
} catch (InvalidProtocolBufferException e) {
showOutput("Unable to parse error result for MetricsConfig " + key.getName()
+ ". " + e.getMessage());
}
}
@Override
public void onAddMetricsConfigStatus(@NonNull MetricsConfigKey key, int statusCode) {
showOutput("Add MetricsConfig status: " + statusCode);
}
}
}