Dump contexthub in protobuf format

Add protobuf dumpsys of connmetrics. Primarily used by incident service
to capture an incident report proto.

Command to invoke (any of the following after lunch and env setup):
$ adb shell dumpsys contexthub --proto
$ adb shell incident 3051
$ incident_report 3051

Bug: 146086599
Test: $ incident_report 3051, then compare the content with "dumpsys
      contexthub"

Change-Id: I6c2ed76a1a17f9bfc60d07e68cd66d5eea00e9b0
This commit is contained in:
Mike Ma
2020-01-15 17:26:24 -08:00
parent 881254f4cb
commit ac0cae7c48
7 changed files with 225 additions and 10 deletions

View File

@@ -21,6 +21,7 @@ import android.annotation.SystemApi;
import android.hardware.contexthub.V1_0.ContextHub;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.proto.ProtoOutputStream;
import java.util.Arrays;
@@ -270,6 +271,30 @@ public class ContextHubInfo implements Parcelable {
return retVal;
}
/**
* Dump the internal state as a ContextHubInfoProto to the given ProtoOutputStream.
*
* If the output belongs to a sub message, the caller is responsible for wrapping this function
* between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
*
* @hide
*/
public void dump(ProtoOutputStream proto) {
proto.write(ContextHubInfoProto.ID, mId);
proto.write(ContextHubInfoProto.NAME, mName);
proto.write(ContextHubInfoProto.VENDOR, mVendor);
proto.write(ContextHubInfoProto.TOOLCHAIN, mToolchain);
proto.write(ContextHubInfoProto.PLATFORM_VERSION, mPlatformVersion);
proto.write(ContextHubInfoProto.STATIC_SW_VERSION, getStaticSwVersion());
proto.write(ContextHubInfoProto.TOOLCHAIN_VERSION, mToolchainVersion);
proto.write(ContextHubInfoProto.CHRE_PLATFORM_ID, mChrePlatformId);
proto.write(ContextHubInfoProto.PEAK_MIPS, mPeakMips);
proto.write(ContextHubInfoProto.STOPPED_POWER_DRAW_MW, mStoppedPowerDrawMw);
proto.write(ContextHubInfoProto.SLEEP_POWER_DRAW_MW, mSleepPowerDrawMw);
proto.write(ContextHubInfoProto.PEAK_POWER_DRAW_MW, mPeakPowerDrawMw);
proto.write(ContextHubInfoProto.MAX_PACKET_LENGTH_BYTES, mMaxPacketLengthBytes);
}
@Override
public boolean equals(@Nullable Object object) {
if (object == this) {

View File

@@ -0,0 +1,49 @@
/*
* 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 android.hardware.location;
import "frameworks/base/core/proto/android/privacy.proto";
option java_multiple_files = true;
message ContextHubInfoProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
// Context hub unique identifier
optional int32 id = 1;
// A name for the hub
optional string name = 2;
// A name for the vendor
optional string vendor = 3;
// Description of the tool chain
optional string toolchain = 4;
optional int32 platform_version = 5;
optional int32 static_sw_version = 6;
optional int32 toolchain_version = 7;
// The CHRE platform ID as defined in chre/version.h
optional int64 chre_platform_id = 8;
// Peak MIPS that this hub can deliver
optional float peak_mips = 9;
// Power draw in stopped state in milli watts
optional float stopped_power_draw_mw = 10;
// Power draw in sleep state in milli watts
optional float sleep_power_draw_mw = 11;
// Peak power draw in milli watts
optional float peak_power_draw_mw = 12;
// The maximum number of bytes that can be sent per message to the hub
optional int32 max_packet_length_bytes = 13;
}

View File

@@ -36,6 +36,7 @@ import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
import "frameworks/base/core/proto/android/server/fingerprint.proto";
import "frameworks/base/core/proto/android/server/jobscheduler.proto";
import "frameworks/base/core/proto/android/server/location/context_hub.proto";
import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
import "frameworks/base/core/proto/android/server/rolemanagerservice.proto";
import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
@@ -486,6 +487,11 @@ message IncidentProto {
(section).args = "connmetrics --proto"
];
optional com.android.server.location.ContextHubServiceProto context_hub = 3051 [
(section).type = SECTION_DUMPSYS,
(section).args = "contexthub --proto"
];
// Reserved for OEMs.
extensions 50000 to 100000;
}

View File

@@ -0,0 +1,60 @@
/*
* 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 com.android.server.location;
import "frameworks/base/core/proto/android/hardware/location/context_hub_info.proto";
import "frameworks/base/core/proto/android/privacy.proto";
option java_multiple_files = true;
message ContextHubServiceProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
repeated .android.hardware.location.ContextHubInfoProto context_hub_info = 1;
optional ClientManagerProto client_manager = 2;
}
message ClientManagerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
message RegistrationRecord {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int64 timestamp_ms = 1;
optional int32 action = 2;
// ClientBroker endpoint id, contexthub id and package name
optional string broker = 3;
}
repeated ClientBrokerProto client_brokers = 1;
repeated RegistrationRecord registration_records = 2;
}
message ClientBrokerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 endpoint_id = 1;
optional int32 attached_context_hub_id = 2;
optional string package = 3;
optional int64 nano_app_id = 4;
optional bool pending_intent_request_valid = 5;
optional bool has_pending_intent = 6;
optional bool pending_intent_cancelled = 7;
optional bool registered = 8;
}

View File

@@ -33,6 +33,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
@@ -449,6 +450,28 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
}
}
/**
* Dump debugging info as ClientBrokerProto
*
* If the output belongs to a sub message, the caller is responsible for wrapping this function
* between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
*
* @param proto the ProtoOutputStream to write to
*/
void dump(ProtoOutputStream proto) {
proto.write(ClientBrokerProto.ENDPOINT_ID, getHostEndPointId());
proto.write(ClientBrokerProto.ATTACHED_CONTEXT_HUB_ID, getAttachedContextHubId());
proto.write(ClientBrokerProto.PACKAGE, mPackage);
if (mPendingIntentRequest.isValid()) {
proto.write(ClientBrokerProto.PENDING_INTENT_REQUEST_VALID, true);
proto.write(ClientBrokerProto.NANO_APP_ID, mPendingIntentRequest.getNanoAppId());
}
proto.write(ClientBrokerProto.HAS_PENDING_INTENT, mPendingIntentRequest.hasPendingIntent());
proto.write(ClientBrokerProto.PENDING_INTENT_CANCELLED, isPendingIntentCancelled());
proto.write(ClientBrokerProto.REGISTERED, mRegistered);
}
@Override
public String toString() {
String out = "[ContextHubClient ";

View File

@@ -27,10 +27,13 @@ import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
import android.os.RemoteException;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Calendar;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
@@ -44,6 +47,11 @@ import java.util.function.Consumer;
/* package */ class ContextHubClientManager {
private static final String TAG = "ContextHubClientManager";
/*
* The DateFormat for printing RegistrationRecord.
*/
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd HH:mm:ss.SSS");
/*
* The maximum host endpoint ID value that a client can be assigned.
*/
@@ -123,24 +131,24 @@ import java.util.function.Consumer;
private class RegistrationRecord {
private final String mBroker;
private final int mAction;
private final String mDate;
private final long mTimestamp;
RegistrationRecord(String broker, @Action int action) {
mBroker = broker;
mAction = action;
Calendar instance = Calendar.getInstance();
mDate = String.format("%02d", instance.get(Calendar.MONTH) + 1) // Jan == 0
+ "/" + String.format("%02d", instance.get(Calendar.DAY_OF_MONTH))
+ " " + String.format("%02d", instance.get(Calendar.HOUR_OF_DAY))
+ ":" + String.format("%02d", instance.get(Calendar.MINUTE))
+ ":" + String.format("%02d", instance.get(Calendar.SECOND))
+ "." + String.format("%03d", instance.get(Calendar.MILLISECOND));
mTimestamp = System.currentTimeMillis();
}
void dump(ProtoOutputStream proto) {
proto.write(ClientManagerProto.RegistrationRecord.TIMESTAMP_MS, mTimestamp);
proto.write(ClientManagerProto.RegistrationRecord.ACTION, mAction);
proto.write(ClientManagerProto.RegistrationRecord.BROKER, mBroker);
}
@Override
public String toString() {
String out = "";
out += mDate + " ";
out += DATE_FORMAT.format(new Date(mTimestamp)) + " ";
out += mAction == ACTION_REGISTERED ? "+ " : "- ";
out += mBroker;
if (mAction == ACTION_CANCELLED) {
@@ -376,6 +384,28 @@ import java.util.function.Consumer;
return null;
}
/**
* Dump debugging info as ClientManagerProto
*
* If the output belongs to a sub message, the caller is responsible for wrapping this function
* between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
*
* @param proto the ProtoOutputStream to write to
*/
void dump(ProtoOutputStream proto) {
for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
long token = proto.start(ClientManagerProto.CLIENT_BROKERS);
broker.dump(proto);
proto.end(token);
}
Iterator<RegistrationRecord> it = mRegistrationRecordDeque.descendingIterator();
while (it.hasNext()) {
long token = proto.start(ClientManagerProto.REGISTRATION_RECORDS);
it.next().dump(proto);
proto.end(token);
}
}
@Override
public String toString() {
String out = "";

View File

@@ -43,6 +43,7 @@ import android.hardware.location.NanoAppState;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.DumpUtils;
@@ -782,6 +783,13 @@ public class ContextHubService extends IContextHubService.Stub {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
for (String arg : args) {
if ("--proto".equals(arg)) {
dump(new ProtoOutputStream(fd));
return;
}
}
pw.println("Dumping ContextHub Service");
pw.println("");
@@ -802,6 +810,20 @@ public class ContextHubService extends IContextHubService.Stub {
// dump eventLog
}
private void dump(ProtoOutputStream proto) {
mContextHubIdToInfoMap.values().forEach(hubInfo -> {
long token = proto.start(ContextHubServiceProto.CONTEXT_HUB_INFO);
hubInfo.dump(proto);
proto.end(token);
});
long token = proto.start(ContextHubServiceProto.CLIENT_MANAGER);
mClientManager.dump(proto);
proto.end(token);
proto.flush();
}
private void checkPermissions() {
ContextHubServiceUtil.checkPermissions(mContext);
}