summaryrefslogtreecommitdiffstats
path: root/services/core/java/com/android/server/trust
diff options
context:
space:
mode:
authorAdrian Roos <roosa@google.com>2014-05-02 12:12:20 +0200
committerAdrian Roos <roosa@google.com>2014-05-20 16:46:36 +0200
commit7a4f3d448b17b4bea190c906d7ecc7f8bec9ff80 (patch)
tree40c77560b388db4658bad8aa76a34e3c5b07b983 /services/core/java/com/android/server/trust
parent47c6514eaa5f1b0af101108b3c1b599cefa14b23 (diff)
downloadframeworks_base-7a4f3d448b17b4bea190c906d7ecc7f8bec9ff80.zip
frameworks_base-7a4f3d448b17b4bea190c906d7ecc7f8bec9ff80.tar.gz
frameworks_base-7a4f3d448b17b4bea190c906d7ecc7f8bec9ff80.tar.bz2
Add dumpsys facility and a history to TrustManagerService
TrustManagerService now keeps track of all events that influence its state and reports them when it is dumped or a bugreport is collected. Bug: 15079129 Change-Id: Iac13de8a848d2b12c8d06168a6969f55b264144a
Diffstat (limited to 'services/core/java/com/android/server/trust')
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java40
-rw-r--r--services/core/java/com/android/server/trust/TrustArchive.java159
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java59
3 files changed, 248 insertions, 10 deletions
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index d8d3da1..47ce3b6 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -20,7 +20,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -39,10 +38,15 @@ public class TrustAgentWrapper {
private static final boolean DEBUG = false;
private static final String TAG = "TrustAgentWrapper";
- private static final int MSG_ENABLE_TRUST = 1;
+ private static final int MSG_GRANT_TRUST = 1;
private static final int MSG_REVOKE_TRUST = 2;
private static final int MSG_TRUST_TIMEOUT = 3;
+ /**
+ * Long extra for {@link #MSG_GRANT_TRUST}
+ */
+ private static final String DATA_DURATION = "duration";
+
private final TrustManagerService mTrustManagerService;
private final int mUserId;
private final Context mContext;
@@ -58,19 +62,32 @@ public class TrustAgentWrapper {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_ENABLE_TRUST:
+ case MSG_GRANT_TRUST:
mTrusted = true;
mMessage = (CharSequence) msg.obj;
boolean initiatedByUser = msg.arg1 != 0;
- // TODO: Handle handle user initiated trust changes.
+ // TODO: Handle initiatedByUser.
+ long durationMs = msg.getData().getLong(DATA_DURATION);
+ if (durationMs > 0) {
+ mHandler.removeMessages(MSG_TRUST_TIMEOUT);
+ mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
+ }
+ mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
+ (mMessage != null ? mMessage.toString() : null),
+ durationMs, initiatedByUser);
mTrustManagerService.updateTrust(mUserId);
break;
case MSG_TRUST_TIMEOUT:
if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
+ mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
// Fall through.
case MSG_REVOKE_TRUST:
mTrusted = false;
mMessage = null;
+ mHandler.removeMessages(MSG_TRUST_TIMEOUT);
+ if (msg.what == MSG_REVOKE_TRUST) {
+ mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
+ }
mTrustManagerService.updateTrust(mUserId);
break;
}
@@ -84,12 +101,10 @@ public class TrustAgentWrapper {
if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
+ ", initiatedByUser = " + initiatedByUser + ")");
- mHandler.obtainMessage(MSG_ENABLE_TRUST, initiatedByUser ? 1 : 0, 0, userMessage)
- .sendToTarget();
- if (durationMs > 0) {
- mHandler.removeMessages(MSG_TRUST_TIMEOUT);
- mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
- }
+ Message msg = mHandler.obtainMessage(
+ MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage);
+ msg.getData().putLong(DATA_DURATION, durationMs);
+ msg.sendToTarget();
}
@Override
@@ -111,6 +126,7 @@ public class TrustAgentWrapper {
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
mTrustAgentService = null;
+ mTrustManagerService.mArchive.logAgentDied(mUserId, name);
mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
}
};
@@ -165,4 +181,8 @@ public class TrustAgentWrapper {
if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
mContext.unbindService(mConnection);
}
+
+ public boolean isConnected() {
+ return mTrustAgentService != null;
+ }
}
diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java
new file mode 100644
index 0000000..aad156c
--- /dev/null
+++ b/services/core/java/com/android/server/trust/TrustArchive.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 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.android.server.trust;
+
+import android.content.ComponentName;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayDeque;
+import java.util.Iterator;
+
+/**
+ * An archive of trust events.
+ */
+public class TrustArchive {
+ private static final int TYPE_GRANT_TRUST = 0;
+ private static final int TYPE_REVOKE_TRUST = 1;
+ private static final int TYPE_TRUST_TIMEOUT = 2;
+ private static final int TYPE_AGENT_DIED = 3;
+
+ private static final int HISTORY_LIMIT = 200;
+
+ private static class Event {
+ final int type;
+ final int userId;
+ final ComponentName agent;
+ final long elapsedTimestamp;
+
+ // grantTrust
+ final String message;
+ final long duration;
+ final boolean userInitiated;
+
+ private Event(int type, int userId, ComponentName agent, String message,
+ long duration, boolean userInitiated) {
+ this.type = type;
+ this.userId = userId;
+ this.agent = agent;
+ this.elapsedTimestamp = SystemClock.elapsedRealtime();
+ this.message = message;
+ this.duration = duration;
+ this.userInitiated = userInitiated;
+ }
+ }
+
+ ArrayDeque<Event> mEvents = new ArrayDeque<Event>();
+
+ public void logGrantTrust(int userId, ComponentName agent, String message,
+ long duration, boolean userInitiated) {
+ addEvent(new Event(TYPE_GRANT_TRUST, userId, agent, message, duration,
+ userInitiated));
+ }
+
+ public void logRevokeTrust(int userId, ComponentName agent) {
+ addEvent(new Event(TYPE_REVOKE_TRUST, userId, agent, null, 0, false));
+ }
+
+ public void logTrustTimeout(int userId, ComponentName agent) {
+ addEvent(new Event(TYPE_TRUST_TIMEOUT, userId, agent, null, 0, false));
+ }
+
+ public void logAgentDied(int userId, ComponentName agent) {
+ addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, false));
+ }
+
+ private void addEvent(Event e) {
+ if (mEvents.size() >= HISTORY_LIMIT) {
+ mEvents.removeFirst();
+ }
+ mEvents.addLast(e);
+ }
+
+ public void dump(PrintWriter writer, int limit, int userId, String linePrefix,
+ boolean duplicateSimpleNames) {
+ int count = 0;
+ Iterator<Event> iter = mEvents.descendingIterator();
+ while (iter.hasNext() && count < limit) {
+ Event ev = iter.next();
+ if (userId != UserHandle.USER_ALL && userId != ev.userId) {
+ continue;
+ }
+
+ writer.print(linePrefix);
+ writer.printf("#%-2d %s %s: ", count, formatElapsed(ev.elapsedTimestamp),
+ dumpType(ev.type));
+ if (userId == UserHandle.USER_ALL) {
+ writer.print("user="); writer.print(ev.userId); writer.print(", ");
+ }
+ writer.print("agent=");
+ if (duplicateSimpleNames) {
+ writer.print(ev.agent.flattenToShortString());
+ } else {
+ writer.print(getSimpleName(ev.agent));
+ }
+ switch (ev.type) {
+ case TYPE_GRANT_TRUST:
+ writer.printf(", message=\"%s\", duration=%s",
+ ev.message, formatDuration(ev.duration));
+ break;
+ default:
+ }
+ writer.println();
+ count++;
+ }
+ }
+
+ private static String formatDuration(long duration) {
+ StringBuilder sb = new StringBuilder();
+ TimeUtils.formatDuration(duration, sb);
+ return sb.toString();
+ }
+
+ private static String formatElapsed(long elapsed) {
+ long delta = elapsed - SystemClock.elapsedRealtime();
+ long wallTime = delta + System.currentTimeMillis();
+ return TimeUtils.logTimeOfDay(wallTime);
+ }
+
+ /* package */ static String getSimpleName(ComponentName cn) {
+ String name = cn.getClassName();
+ int idx = name.lastIndexOf('.');
+ if (idx < name.length() && idx >= 0) {
+ return name.substring(idx + 1);
+ } else {
+ return name;
+ }
+ }
+
+ private String dumpType(int type) {
+ switch (type) {
+ case TYPE_GRANT_TRUST:
+ return "GrantTrust";
+ case TYPE_REVOKE_TRUST:
+ return "RevokeTrust";
+ case TYPE_TRUST_TIMEOUT:
+ return "TrustTimeout";
+ case TYPE_AGENT_DIED:
+ return "AgentDied";
+ default:
+ return "Unknown(" + type + ")";
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index efaa91b..986cdc1 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -24,6 +24,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.Manifest;
+import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustListener;
import android.app.trust.ITrustManager;
@@ -52,7 +53,9 @@ import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.Xml;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -87,6 +90,7 @@ public class TrustManagerService extends SystemService {
private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver();
private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
+ /* package */ final TrustArchive mArchive = new TrustArchive();
private final Context mContext;
private UserManager mUserManager;
@@ -367,6 +371,61 @@ public class TrustManagerService extends SystemService {
mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER,
"register trust listener");
}
+
+ @Override
+ protected void dump(FileDescriptor fd, final PrintWriter fout, String[] args) {
+ mContext.enforceCallingPermission(Manifest.permission.DUMP,
+ "dumping TrustManagerService");
+ final UserInfo currentUser;
+ final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
+ try {
+ currentUser = ActivityManagerNative.getDefault().getCurrentUser();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ mHandler.runWithScissors(new Runnable() {
+ @Override
+ public void run() {
+ fout.println("Trust manager state:");
+ for (UserInfo user : userInfos) {
+ dumpUser(fout, user, user.id == currentUser.id);
+ }
+ }
+ }, 1500);
+ }
+
+ private void dumpUser(PrintWriter fout, UserInfo user, boolean isCurrent) {
+ fout.printf(" User \"%s\" (id=%d, flags=%#x)",
+ user.name, user.id, user.flags);
+ if (isCurrent) {
+ fout.print(" (current)");
+ }
+ fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
+ fout.println();
+ fout.println(" Enabled agents:");
+ boolean duplicateSimpleNames = false;
+ ArraySet<String> simpleNames = new ArraySet<String>();
+ for (AgentInfo info : mActiveAgents) {
+ if (info.userId != user.id) { continue; }
+ boolean trusted = info.agent.isTrusted();
+ fout.print(" "); fout.println(info.component.flattenToShortString());
+ fout.print(" connected=" + dumpBool(info.agent.isConnected()));
+ fout.println(", trusted=" + dumpBool(trusted));
+ if (trusted) {
+ fout.println(" message=\"" + info.agent.getMessage() + "\"");
+ }
+ if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) {
+ duplicateSimpleNames = true;
+ }
+ }
+ fout.println(" Events:");
+ mArchive.dump(fout, 50, user.id, " " /* linePrefix */, duplicateSimpleNames);
+ fout.println();
+ }
+
+ private String dumpBool(boolean b) {
+ return b ? "1" : "0";
+ }
};
private final Handler mHandler = new Handler() {