Merge "Implement Activity Manager Dumpsys --service option"
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d5d95fb..42c1347 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -68,6 +68,7 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
import android.view.Gravity;
import android.view.NotificationHeaderView;
import android.view.View;
@@ -2447,6 +2448,30 @@
notification.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, ai);
}
+ /**
+ * @hide
+ */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(NotificationProto.CHANNEL_ID, getChannelId());
+ proto.write(NotificationProto.HAS_TICKER_TEXT, this.tickerText != null);
+ proto.write(NotificationProto.FLAGS, this.flags);
+ proto.write(NotificationProto.COLOR, this.color);
+ proto.write(NotificationProto.CATEGORY, this.category);
+ proto.write(NotificationProto.GROUP_KEY, this.mGroupKey);
+ proto.write(NotificationProto.SORT_KEY, this.mSortKey);
+ if (this.actions != null) {
+ proto.write(NotificationProto.ACTION_LENGTH, this.actions.length);
+ }
+ if (this.visibility >= VISIBILITY_SECRET && this.visibility <= VISIBILITY_PUBLIC) {
+ proto.write(NotificationProto.VISIBILITY, this.visibility);
+ }
+ if (publicVersion != null) {
+ publicVersion.writeToProto(proto, NotificationProto.PUBLIC_VERSION);
+ }
+ proto.end(token);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index 449baca..85b7ec8 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -17,6 +17,7 @@
package android.util.proto;
import android.util.AggStats;
+import android.util.Duration;
/**
* This class contains a list of helper functions to write common proto in
@@ -36,4 +37,15 @@
proto.write(AggStats.MAX, max);
proto.end(aggStatsToken);
}
+
+ /**
+ * Dump Duration to ProtoOutputStream
+ * @hide
+ */
+ public static void toDuration(ProtoOutputStream proto, long fieldId, long startMs, long endMs) {
+ final long token = proto.start(fieldId);
+ proto.write(Duration.START_MS, startMs);
+ proto.write(Duration.END_MS, endMs);
+ proto.end(token);
+ }
}
diff --git a/core/proto/android/app/notification.proto b/core/proto/android/app/notification.proto
new file mode 100644
index 0000000..5376b0e
--- /dev/null
+++ b/core/proto/android/app/notification.proto
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+option java_package = "android.app";
+option java_multiple_files = true;
+
+package android.app;
+
+/**
+ * An android.app.Notification object.
+ * Deprecated fields are not included in the proto.
+ */
+message NotificationProto {
+ optional string channel_id = 1;
+ optional bool has_ticker_text = 2;
+ optional int32 flags = 3;
+ optional int32 color = 4;
+ optional string category = 5;
+ optional string group_key = 6;
+ optional string sort_key = 7;
+ optional int32 action_length = 8;
+
+ // If this field is not set, then the value is unknown.
+ enum Visibility {
+ VISIBILITY_SECRET = -1;
+ VISIBILITY_PRIVATE = 0;
+ VISIBILITY_PUBLIC = 1;
+ }
+ optional Visibility visibility = 9;
+ optional NotificationProto public_version = 10;
+}
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index f68f3a4..6c5206c 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -143,7 +143,11 @@
(section).args = "activity --proto broadcasts"
];
- optional com.android.server.am.proto.ServiceProto amservices = 3014;
+ optional com.android.server.am.proto.ActiveServicesProto amservices = 3014 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "activity --proto service"
+ ];
+
optional com.android.server.am.proto.ProcessProto amprocesses = 3015;
optional com.android.server.AlarmManagerServiceProto alarm = 3016 [
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index c57cb72..889842c 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -15,11 +15,14 @@
*/
syntax = "proto2";
+
+import "frameworks/base/core/proto/android/app/notification.proto";
import "frameworks/base/core/proto/android/content/intent.proto";
import "frameworks/base/core/proto/android/server/intentresolver.proto";
import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/graphics/rect.proto";
import "frameworks/base/core/proto/android/os/looper.proto";
+import "frameworks/base/core/proto/android/util/common.proto";
package com.android.server.am.proto;
@@ -30,11 +33,12 @@
optional BroadcastProto broadcasts = 2;
- optional ServiceProto services = 3;
+ optional ActiveServicesProto services = 3;
optional ProcessProto processes = 4;
}
+// "dumpsys activity --proto activities"
message ActivityStackSupervisorProto {
optional .com.android.server.wm.proto.ConfigurationContainerProto configuration_container = 1;
repeated ActivityDisplayProto displays = 2;
@@ -90,6 +94,7 @@
optional bool keyguard_occluded = 2;
}
+// "dumpsys activity --proto broadcasts"
message BroadcastProto {
repeated ReceiverListProto receiver_list = 1;
@@ -164,10 +169,158 @@
repeated StickyAction actions = 2;
}
-message ServiceProto {
- // TODO: "dumpsys activity --proto services"
+// "dumpsys activity --proto service"
+message ActiveServicesProto {
+
+ message ServicesByUser {
+ optional int32 user_id = 1;
+ repeated ServiceRecordProto service_records = 2;
+ }
+ repeated ServicesByUser services_by_users = 1;
}
+// corresponds to ActivityManagerService.GrantUri Java class
+message GrantUriProto {
+ optional int32 source_user_id = 1;
+ optional string uri = 2;
+}
+
+message NeededUriGrantsProto {
+ optional string target_package = 1;
+ optional int32 target_uid = 2;
+ optional int32 flags = 3;
+
+ repeated GrantUriProto grants = 4;
+}
+
+message UriPermissionOwnerProto {
+ optional string owner = 1;
+ repeated GrantUriProto read_perms = 2;
+ repeated GrantUriProto write_perms = 3;
+}
+
+message ServiceRecordProto {
+ optional string short_name = 1;
+ optional string hex_hash = 2;
+ optional bool is_running = 3; // false if the application service is null
+ optional int32 pid = 4;
+ optional .android.content.IntentProto intent = 5;
+ optional string package_name = 6;
+ optional string process_name = 7;
+ optional string permission = 8;
+
+ message AppInfo {
+ optional string base_dir = 1;
+ optional string res_dir = 2;
+ optional string data_dir = 3;
+ }
+ optional AppInfo appinfo = 9;
+ optional ProcessRecordProto app = 10;
+ optional ProcessRecordProto isolated_proc = 11;
+ optional bool whitelist_manager = 12;
+ optional bool delayed = 13;
+
+ message Foreground {
+ optional int32 id = 1;
+ optional .android.app.NotificationProto notification = 2;
+ }
+ optional Foreground foreground = 14;
+
+ optional .android.util.Duration create_real_time = 15;
+ optional .android.util.Duration starting_bg_timeout = 16;
+ optional .android.util.Duration last_activity_time = 17;
+ optional .android.util.Duration restart_time = 18;
+ optional bool created_from_fg = 19;
+
+ // variables used to track states related to service start
+ message Start {
+ optional bool start_requested = 1;
+ optional bool delayed_stop = 2;
+ optional bool stop_if_killed = 3;
+ optional bool call_start = 4;
+ optional int32 last_start_id = 5;
+ }
+ optional Start start = 20;
+
+ message ExecuteNesting {
+ optional int32 execute_nesting = 1;
+ optional bool execute_fg = 2;
+ optional .android.util.Duration executing_start = 3;
+ }
+ optional ExecuteNesting execute = 21;
+
+ optional .android.util.Duration destory_time = 22;
+
+ message Crash {
+ optional int32 restart_count = 1;
+ optional .android.util.Duration restart_delay = 2;
+ optional .android.util.Duration next_restart_time = 3;
+ optional int32 crash_count = 4;
+ }
+ optional Crash crash = 23;
+
+ message StartItemProto {
+ optional int32 id = 1;
+ optional .android.util.Duration duration = 2;
+ optional int32 delivery_count = 3;
+ optional int32 done_executing_count = 4;
+ optional .android.content.IntentProto intent = 5;
+ optional NeededUriGrantsProto needed_grants = 6;
+ optional UriPermissionOwnerProto uri_permissions = 7;
+ }
+ repeated StartItemProto delivered_starts = 24;
+ repeated StartItemProto pending_starts = 25;
+
+ repeated IntentBindRecordProto bindings = 26;
+ repeated ConnectionRecordProto connections = 27;
+}
+
+message ConnectionRecordProto {
+ optional string hex_hash = 1;
+ optional int32 user_id = 2;
+
+ enum Flag {
+ AUTO_CREATE = 0;
+ DEBUG_UNBIND = 1;
+ NOT_FG = 2;
+ IMPORTANT_BG = 3;
+ ABOVE_CLIENT = 4;
+ ALLOW_OOM_MANAGEMENT = 5;
+ WAIVE_PRIORITY = 6;
+ IMPORTANT = 7;
+ ADJUST_WITH_ACTIVITY = 8;
+ FG_SERVICE_WHILE_WAKE = 9;
+ FG_SERVICE = 10;
+ TREAT_LIKE_ACTIVITY = 11;
+ VISIBLE = 12;
+ SHOWING_UI = 13;
+ NOT_VISIBLE = 14;
+ DEAD = 15;
+ }
+ repeated Flag flags = 3;
+ optional string service_name = 4;
+ optional string conn_hex_hash = 5;
+}
+
+message AppBindRecordProto {
+ optional string hex_hash = 1;
+ optional ProcessRecordProto client = 2;
+ repeated ConnectionRecordProto connections = 3;
+}
+
+message IntentBindRecordProto {
+ optional string hex_hash = 1;
+ optional bool is_create = 2;
+ optional .android.content.IntentProto intent = 3;
+ optional string binder = 4;
+ optional bool requested = 5;
+ optional bool received = 6;
+ optional bool has_bound = 7;
+ optional bool do_rebind = 8;
+
+ repeated AppBindRecordProto apps = 9;
+}
+
+// TODO: "dumpsys activity --proto processes"
message ProcessProto {
- // TODO: "dumpsys activity --proto processes"
}
diff --git a/core/proto/android/util/common.proto b/core/proto/android/util/common.proto
index 429c3cad..308ef70 100644
--- a/core/proto/android/util/common.proto
+++ b/core/proto/android/util/common.proto
@@ -30,3 +30,13 @@
optional int64 max = 3;
}
+
+/**
+ * Very basic data structure to represent Duration.
+ */
+message Duration {
+
+ optional int64 start_ms = 1;
+
+ optional int64 end_ms = 2;
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 701c574..3cd2f6a 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -58,6 +58,7 @@
import com.android.internal.util.FastPrintWriter;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityManagerService.NeededUriGrants;
+import com.android.server.am.proto.ActiveServicesProto;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -85,6 +86,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
import android.webkit.WebViewZygote;
public final class ActiveServices {
@@ -633,7 +635,7 @@
sb.append("Stopping service due to app idle: ");
UserHandle.formatUid(sb, service.appInfo.uid);
sb.append(" ");
- TimeUtils.formatDuration(service.createTime
+ TimeUtils.formatDuration(service.createRealTime
- SystemClock.elapsedRealtime(), sb);
sb.append(" ");
sb.append(compName);
@@ -3220,7 +3222,7 @@
info.uid = r.appInfo.uid;
info.process = r.processName;
info.foreground = r.isForeground;
- info.activeSince = r.createTime;
+ info.activeSince = r.createRealTime;
info.started = r.startRequested;
info.clientCount = r.connections.size();
info.crashCount = r.crashCount;
@@ -3574,7 +3576,7 @@
pw.print(" app=");
pw.println(r.app);
pw.print(" created=");
- TimeUtils.formatDuration(r.createTime, nowReal, pw);
+ TimeUtils.formatDuration(r.createRealTime, nowReal, pw);
pw.print(" started=");
pw.print(r.startRequested);
pw.print(" connections=");
@@ -3840,6 +3842,26 @@
return new ServiceDumper(fd, pw, args, opti, dumpAll, dumpPackage);
}
+ protected void writeToProto(ProtoOutputStream proto) {
+ synchronized (mAm) {
+ int[] users = mAm.mUserController.getUsers();
+ for (int user : users) {
+ ServiceMap smap = mServiceMap.get(user);
+ if (smap == null) {
+ continue;
+ }
+ long token = proto.start(ActiveServicesProto.SERVICES_BY_USERS);
+ proto.write(ActiveServicesProto.ServicesByUser.USER_ID, user);
+ ArrayMap<ComponentName, ServiceRecord> alls = smap.mServicesByName;
+ for (int i=0; i<alls.size(); i++) {
+ alls.valueAt(i).writeToProto(proto,
+ ActiveServicesProto.ServicesByUser.SERVICE_RECORDS);
+ }
+ proto.end(token);
+ }
+ }
+ }
+
/**
* There are three ways to call this:
* - no service specified: dump all the services
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fe5c789..b3b831e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -415,6 +415,8 @@
import com.android.server.am.ActivityStack.ActivityState;
import com.android.server.am.proto.ActivityManagerServiceProto;
import com.android.server.am.proto.BroadcastProto;
+import com.android.server.am.proto.GrantUriProto;
+import com.android.server.am.proto.NeededUriGrantsProto;
import com.android.server.am.proto.StickyBroadcastProto;
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
@@ -1191,6 +1193,13 @@
return result;
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(GrantUriProto.URI, uri.toString());
+ proto.write(GrantUriProto.SOURCE_USER_ID, sourceUserId);
+ proto.end(token);
+ }
+
public static GrantUri resolve(int defaultSourceUserHandle, Uri uri) {
return new GrantUri(ContentProvider.getUserIdFromUri(uri, defaultSourceUserHandle),
ContentProvider.getUriWithoutUserId(uri), false);
@@ -9044,6 +9053,19 @@
this.targetUid = targetUid;
this.flags = flags;
}
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(NeededUriGrantsProto.TARGET_PACKAGE, targetPkg);
+ proto.write(NeededUriGrantsProto.TARGET_UID, targetUid);
+ proto.write(NeededUriGrantsProto.FLAGS, flags);
+
+ final int N = this.size();
+ for (int i=0; i<N; i++) {
+ this.get(i).writeToProto(proto, NeededUriGrantsProto.GRANTS);
+ }
+ proto.end(token);
+ }
}
/**
@@ -14939,6 +14961,8 @@
pw.println("No providers match: " + name);
pw.println("Use -h for help.");
}
+ } else if ("service".equals(cmd)) {
+ mServices.writeToProto(proto);
} else {
// default option, dump everything, output is ActivityManagerServiceProto
synchronized (this) {
@@ -14949,6 +14973,10 @@
long broadcastToken = proto.start(ActivityManagerServiceProto.BROADCASTS);
writeBroadcastsToProtoLocked(proto);
proto.end(broadcastToken);
+
+ long serviceToken = proto.start(ActivityManagerServiceProto.SERVICES);
+ mServices.writeToProto(proto);
+ proto.end(serviceToken);
}
}
proto.flush();
diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
index df833ad..7b38597 100644
--- a/services/core/java/com/android/server/am/AppBindRecord.java
+++ b/services/core/java/com/android/server/am/AppBindRecord.java
@@ -17,6 +17,9 @@
package com.android.server.am;
import android.util.ArraySet;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.proto.AppBindRecordProto;
import java.io.PrintWriter;
@@ -60,4 +63,18 @@
+ Integer.toHexString(System.identityHashCode(this))
+ " " + service.shortName + ":" + client.processName + "}";
}
+
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(AppBindRecordProto.HEX_HASH,
+ Integer.toHexString(System.identityHashCode(this)));
+ if (client != null) {
+ client.writeToProto(proto, AppBindRecordProto.CLIENT);
+ }
+ final int N = connections.size();
+ for (int i=0; i<N; i++) {
+ connections.valueAt(i).writeToProto(proto, AppBindRecordProto.CONNECTIONS);
+ }
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index 9b7a0c4..6df283c 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -19,6 +19,9 @@
import android.app.IServiceConnection;
import android.app.PendingIntent;
import android.content.Context;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.proto.ConnectionRecordProto;
import java.io.PrintWriter;
@@ -119,4 +122,70 @@
sb.append('}');
return stringName = sb.toString();
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ if (binding == null) return; // if binding is null, don't write data, something is wrong.
+ long token = proto.start(fieldId);
+ proto.write(ConnectionRecordProto.HEX_HASH,
+ Integer.toHexString(System.identityHashCode(this)));
+ if (binding.client != null) {
+ proto.write(ConnectionRecordProto.USER_ID, binding.client.userId);
+ }
+ if ((flags&Context.BIND_AUTO_CREATE) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.AUTO_CREATE);
+ }
+ if ((flags&Context.BIND_DEBUG_UNBIND) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.DEBUG_UNBIND);
+ }
+ if ((flags&Context.BIND_NOT_FOREGROUND) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.NOT_FG);
+ }
+ if ((flags&Context.BIND_IMPORTANT_BACKGROUND) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.IMPORTANT_BG);
+ }
+ if ((flags&Context.BIND_ABOVE_CLIENT) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.ABOVE_CLIENT);
+ }
+ if ((flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.ALLOW_OOM_MANAGEMENT);
+ }
+ if ((flags&Context.BIND_WAIVE_PRIORITY) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.WAIVE_PRIORITY);
+ }
+ if ((flags&Context.BIND_IMPORTANT) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.IMPORTANT);
+ }
+ if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.ADJUST_WITH_ACTIVITY);
+ }
+ if ((flags&Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.FG_SERVICE_WHILE_WAKE);
+ }
+ if ((flags&Context.BIND_FOREGROUND_SERVICE) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.FG_SERVICE);
+ }
+ if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.TREAT_LIKE_ACTIVITY);
+ }
+ if ((flags&Context.BIND_VISIBLE) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.VISIBLE);
+ }
+ if ((flags&Context.BIND_SHOWING_UI) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.SHOWING_UI);
+ }
+ if ((flags&Context.BIND_NOT_VISIBLE) != 0) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.NOT_VISIBLE);
+ }
+ if (serviceDead) {
+ proto.write(ConnectionRecordProto.FLAGS, ConnectionRecordProto.DEAD);
+ }
+ if (binding.service != null) {
+ proto.write(ConnectionRecordProto.SERVICE_NAME, binding.service.shortName);
+ }
+ if (conn != null) {
+ proto.write(ConnectionRecordProto.CONN_HEX_HASH,
+ Integer.toHexString(System.identityHashCode(conn.asBinder())));
+ }
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
index be290e9..01ce64c 100644
--- a/services/core/java/com/android/server/am/IntentBindRecord.java
+++ b/services/core/java/com/android/server/am/IntentBindRecord.java
@@ -21,6 +21,10 @@
import android.os.IBinder;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.proto.AppBindRecordProto;
+import com.android.server.am.proto.IntentBindRecordProto;
import java.io.PrintWriter;
@@ -106,4 +110,32 @@
sb.append('}');
return stringName = sb.toString();
}
+
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(IntentBindRecordProto.HEX_HASH,
+ Integer.toHexString(System.identityHashCode(this)));
+ proto.write(IntentBindRecordProto.IS_CREATE,
+ (collectFlags()&Context.BIND_AUTO_CREATE) != 0);
+ if (intent != null) {
+ intent.getIntent().writeToProto(proto,
+ IntentBindRecordProto.INTENT, false, true, false, false);
+ }
+ if (binder != null) {
+ proto.write(IntentBindRecordProto.BINDER, binder.toString());
+ }
+ proto.write(IntentBindRecordProto.REQUESTED, requested);
+ proto.write(IntentBindRecordProto.RECEIVED, received);
+ proto.write(IntentBindRecordProto.HAS_BOUND, hasBound);
+ proto.write(IntentBindRecordProto.DO_REBIND, doRebind);
+
+ final int N = apps.size();
+ for (int i=0; i<N; i++) {
+ AppBindRecord a = apps.valueAt(i);
+ if (a != null) {
+ a.writeToProto(proto, IntentBindRecordProto.APPS);
+ }
+ }
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 16995e5..b6eff00 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -19,6 +19,7 @@
import com.android.internal.app.procstats.ServiceState;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.LocalServices;
+import com.android.server.am.proto.ServiceRecordProto;
import com.android.server.notification.NotificationManagerInternal;
import android.app.INotificationManager;
@@ -42,6 +43,8 @@
import android.util.ArrayMap;
import android.util.Slog;
import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+import android.util.proto.ProtoUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -79,7 +82,7 @@
final String permission;// permission needed to access service
final boolean exported; // from ServiceInfo.exported
final Runnable restarter; // used to schedule retries of starting the service
- final long createTime; // when this service was created
+ final long createRealTime; // when this service was created
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
// All active bindings to the service.
@@ -103,7 +106,7 @@
boolean startRequested; // someone explicitly called start?
boolean delayedStop; // service has been stopped but is in a delayed start?
boolean stopIfKilled; // last onStart() said to stop if service killed?
- boolean callStart; // last onStart() has asked to alway be called on restart.
+ boolean callStart; // last onStart() has asked to always be called on restart.
int executeNesting; // number of outstanding operations keeping foreground.
boolean executeFg; // should we be executing in the foreground?
long executingStart; // start time of last execute request.
@@ -159,6 +162,27 @@
}
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
+ long token = proto.start(fieldId);
+ proto.write(ServiceRecordProto.StartItemProto.ID, id);
+ ProtoUtils.toDuration(proto,
+ ServiceRecordProto.StartItemProto.DURATION, deliveredTime, now);
+ proto.write(ServiceRecordProto.StartItemProto.DELIVERY_COUNT, deliveryCount);
+ proto.write(ServiceRecordProto.StartItemProto.DONE_EXECUTING_COUNT, doneExecutingCount);
+ if (intent != null) {
+ intent.writeToProto(proto, ServiceRecordProto.StartItemProto.INTENT, true, true,
+ true, false);
+ }
+ if (neededGrants != null) {
+ neededGrants.writeToProto(proto, ServiceRecordProto.StartItemProto.NEEDED_GRANTS);
+ }
+ if (uriPermissions != null) {
+ uriPermissions.writeToProto(proto,
+ ServiceRecordProto.StartItemProto.URI_PERMISSIONS);
+ }
+ proto.end(token);
+ }
+
public String toString() {
if (stringName != null) {
return stringName;
@@ -209,6 +233,117 @@
}
}
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(ServiceRecordProto.SHORT_NAME, this.shortName);
+ proto.write(ServiceRecordProto.HEX_HASH,
+ Integer.toHexString(System.identityHashCode(this)));
+ proto.write(ServiceRecordProto.IS_RUNNING, app != null);
+ if (app != null) {
+ proto.write(ServiceRecordProto.PID, app.pid);
+ }
+ if (intent != null) {
+ intent.getIntent().writeToProto(proto, ServiceRecordProto.INTENT, false, true, false,
+ true);
+ }
+ proto.write(ServiceRecordProto.PACKAGE_NAME, packageName);
+ proto.write(ServiceRecordProto.PROCESS_NAME, processName);
+ proto.write(ServiceRecordProto.PERMISSION, permission);
+
+ long now = SystemClock.uptimeMillis();
+ long nowReal = SystemClock.elapsedRealtime();
+ if (appInfo != null) {
+ long appInfoToken = proto.start(ServiceRecordProto.APPINFO);
+ proto.write(ServiceRecordProto.AppInfo.BASE_DIR, appInfo.sourceDir);
+ if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
+ proto.write(ServiceRecordProto.AppInfo.RES_DIR, appInfo.publicSourceDir);
+ }
+ proto.write(ServiceRecordProto.AppInfo.DATA_DIR, appInfo.dataDir);
+ proto.end(appInfoToken);
+ }
+ if (app != null) {
+ app.writeToProto(proto, ServiceRecordProto.APP);
+ }
+ if (isolatedProc != null) {
+ isolatedProc.writeToProto(proto, ServiceRecordProto.ISOLATED_PROC);
+ }
+ proto.write(ServiceRecordProto.WHITELIST_MANAGER, whitelistManager);
+ proto.write(ServiceRecordProto.DELAYED, delayed);
+ if (isForeground || foregroundId != 0) {
+ long fgToken = proto.start(ServiceRecordProto.FOREGROUND);
+ proto.write(ServiceRecordProto.Foreground.ID, foregroundId);
+ foregroundNoti.writeToProto(proto, ServiceRecordProto.Foreground.NOTIFICATION);
+ proto.end(fgToken);
+ }
+ ProtoUtils.toDuration(proto, ServiceRecordProto.CREATE_REAL_TIME, createRealTime, nowReal);
+ ProtoUtils.toDuration(proto,
+ ServiceRecordProto.STARTING_BG_TIMEOUT, startingBgTimeout, now);
+ ProtoUtils.toDuration(proto, ServiceRecordProto.LAST_ACTIVITY_TIME, lastActivity, now);
+ ProtoUtils.toDuration(proto, ServiceRecordProto.RESTART_TIME, restartTime, now);
+ proto.write(ServiceRecordProto.CREATED_FROM_FG, createdFromFg);
+
+ if (startRequested || delayedStop || lastStartId != 0) {
+ long startToken = proto.start(ServiceRecordProto.START);
+ proto.write(ServiceRecordProto.Start.START_REQUESTED, startRequested);
+ proto.write(ServiceRecordProto.Start.DELAYED_STOP, delayedStop);
+ proto.write(ServiceRecordProto.Start.STOP_IF_KILLED, stopIfKilled);
+ proto.write(ServiceRecordProto.Start.LAST_START_ID, lastStartId);
+ proto.end(startToken);
+ }
+
+ if (executeNesting != 0) {
+ long executNestingToken = proto.start(ServiceRecordProto.EXECUTE);
+ proto.write(ServiceRecordProto.ExecuteNesting.EXECUTE_NESTING, executeNesting);
+ proto.write(ServiceRecordProto.ExecuteNesting.EXECUTE_FG, executeFg);
+ ProtoUtils.toDuration(proto,
+ ServiceRecordProto.ExecuteNesting.EXECUTING_START, executingStart, now);
+ proto.end(executNestingToken);
+ }
+ if (destroying || destroyTime != 0) {
+ ProtoUtils.toDuration(proto, ServiceRecordProto.DESTORY_TIME, destroyTime, now);
+ }
+ if (crashCount != 0 || restartCount != 0 || restartDelay != 0 || nextRestartTime != 0) {
+ long crashToken = proto.start(ServiceRecordProto.CRASH);
+ proto.write(ServiceRecordProto.Crash.RESTART_COUNT, restartCount);
+ ProtoUtils.toDuration(proto, ServiceRecordProto.Crash.RESTART_DELAY, restartDelay, now);
+ ProtoUtils.toDuration(proto,
+ ServiceRecordProto.Crash.NEXT_RESTART_TIME, nextRestartTime, now);
+ proto.write(ServiceRecordProto.Crash.CRASH_COUNT, crashCount);
+ proto.end(crashToken);
+ }
+
+ if (deliveredStarts.size() > 0) {
+ final int N = deliveredStarts.size();
+ for (int i = 0; i < N; i++) {
+ deliveredStarts.get(i).writeToProto(proto,
+ ServiceRecordProto.DELIVERED_STARTS, now);
+ }
+ }
+ if (pendingStarts.size() > 0) {
+ final int N = pendingStarts.size();
+ for (int i = 0; i < N; i++) {
+ pendingStarts.get(i).writeToProto(proto, ServiceRecordProto.PENDING_STARTS, now);
+ }
+ }
+ if (bindings.size() > 0) {
+ final int N = bindings.size();
+ for (int i=0; i<N; i++) {
+ IntentBindRecord b = bindings.valueAt(i);
+ b.writeToProto(proto, ServiceRecordProto.BINDINGS);
+ }
+ }
+ if (connections.size() > 0) {
+ final int N = connections.size();
+ for (int conni=0; conni<N; conni++) {
+ ArrayList<ConnectionRecord> c = connections.valueAt(conni);
+ for (int i=0; i<c.size(); i++) {
+ c.get(i).writeToProto(proto, ServiceRecordProto.CONNECTIONS);
+ }
+ }
+ }
+ proto.end(token);
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
pw.print(intent.getIntent().toShortString(false, true, false, true));
@@ -243,7 +378,7 @@
pw.print(" foregroundNoti="); pw.println(foregroundNoti);
}
pw.print(prefix); pw.print("createTime=");
- TimeUtils.formatDuration(createTime, nowReal, pw);
+ TimeUtils.formatDuration(createRealTime, nowReal, pw);
pw.print(" startingBgTimeout=");
TimeUtils.formatDuration(startingBgTimeout, now, pw);
pw.println();
@@ -329,7 +464,7 @@
permission = sInfo.permission;
exported = sInfo.exported;
this.restarter = restarter;
- createTime = SystemClock.elapsedRealtime();
+ createRealTime = SystemClock.elapsedRealtime();
lastActivity = SystemClock.uptimeMillis();
userId = UserHandle.getUserId(appInfo.uid);
createdFromFg = callerIsFg;
diff --git a/services/core/java/com/android/server/am/UriPermissionOwner.java b/services/core/java/com/android/server/am/UriPermissionOwner.java
index 28344df..fc07c1a 100644
--- a/services/core/java/com/android/server/am/UriPermissionOwner.java
+++ b/services/core/java/com/android/server/am/UriPermissionOwner.java
@@ -20,6 +20,9 @@
import android.os.Binder;
import android.os.IBinder;
import android.util.ArraySet;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.am.proto.UriPermissionOwnerProto;
import com.google.android.collect.Sets;
@@ -139,6 +142,26 @@
}
}
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(UriPermissionOwnerProto.OWNER, owner.toString());
+ if (mReadPerms != null) {
+ synchronized (mReadPerms) {
+ for (UriPermission p : mReadPerms) {
+ p.uri.writeToProto(proto, UriPermissionOwnerProto.READ_PERMS);
+ }
+ }
+ }
+ if (mWritePerms != null) {
+ synchronized (mWritePerms) {
+ for (UriPermission p : mWritePerms) {
+ p.uri.writeToProto(proto, UriPermissionOwnerProto.WRITE_PERMS);
+ }
+ }
+ }
+ proto.end(token);
+ }
+
@Override
public String toString() {
return owner.toString();