Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit efb5d8d3 authored by Adrian Roos's avatar Adrian Roos Committed by Android (Google) Code Review
Browse files

Merge "Add dumpsys facility and a history to TrustManagerService"

parents b979f23c 7a4f3d44
Loading
Loading
Loading
Loading
+30 −10
Original line number Diff line number Diff line
@@ -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;
    }
}
+159 −0
Original line number Diff line number Diff line
/*
 * 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 + ")";
        }
    }
}
+59 −0
Original line number Diff line number Diff line
@@ -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() {