1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.trust;
18
19import android.content.ComponentName;
20import android.os.SystemClock;
21import android.os.UserHandle;
22import android.service.trust.TrustAgentService;
23import android.util.TimeUtils;
24
25import java.io.PrintWriter;
26import java.util.ArrayDeque;
27import java.util.Iterator;
28
29/**
30 * An archive of trust events.
31 */
32public class TrustArchive {
33    private static final int TYPE_GRANT_TRUST = 0;
34    private static final int TYPE_REVOKE_TRUST = 1;
35    private static final int TYPE_TRUST_TIMEOUT = 2;
36    private static final int TYPE_AGENT_DIED = 3;
37    private static final int TYPE_AGENT_CONNECTED = 4;
38    private static final int TYPE_AGENT_STOPPED = 5;
39    private static final int TYPE_MANAGING_TRUST = 6;
40
41    private static final int HISTORY_LIMIT = 200;
42
43    private static class Event {
44        final int type;
45        final int userId;
46        final ComponentName agent;
47        final long elapsedTimestamp;
48
49        // grantTrust
50        final String message;
51        final long duration;
52        final int flags;
53
54        // managingTrust
55        final boolean managingTrust;
56
57        private Event(int type, int userId, ComponentName agent, String message,
58                long duration, int flags, boolean managingTrust) {
59            this.type = type;
60            this.userId = userId;
61            this.agent = agent;
62            this.elapsedTimestamp = SystemClock.elapsedRealtime();
63            this.message = message;
64            this.duration = duration;
65            this.flags = flags;
66            this.managingTrust = managingTrust;
67        }
68    }
69
70    ArrayDeque<Event> mEvents = new ArrayDeque<Event>();
71
72    public void logGrantTrust(int userId, ComponentName agent, String message,
73            long duration, int flags) {
74        addEvent(new Event(TYPE_GRANT_TRUST, userId, agent, message, duration,
75                flags, false));
76    }
77
78    public void logRevokeTrust(int userId, ComponentName agent) {
79        addEvent(new Event(TYPE_REVOKE_TRUST, userId, agent, null, 0, 0, false));
80    }
81
82    public void logTrustTimeout(int userId, ComponentName agent) {
83        addEvent(new Event(TYPE_TRUST_TIMEOUT, userId, agent, null, 0, 0, false));
84    }
85
86    public void logAgentDied(int userId, ComponentName agent) {
87        addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, 0, false));
88    }
89
90    public void logAgentConnected(int userId, ComponentName agent) {
91        addEvent(new Event(TYPE_AGENT_CONNECTED, userId, agent, null, 0, 0, false));
92    }
93
94    public void logAgentStopped(int userId, ComponentName agent) {
95        addEvent(new Event(TYPE_AGENT_STOPPED, userId, agent, null, 0, 0, false));
96    }
97
98    public void logManagingTrust(int userId, ComponentName agent, boolean managing) {
99        addEvent(new Event(TYPE_MANAGING_TRUST, userId, agent, null, 0, 0, managing));
100    }
101
102    private void addEvent(Event e) {
103        if (mEvents.size() >= HISTORY_LIMIT) {
104            mEvents.removeFirst();
105        }
106        mEvents.addLast(e);
107    }
108
109    public void dump(PrintWriter writer, int limit, int userId, String linePrefix,
110            boolean duplicateSimpleNames) {
111        int count = 0;
112        Iterator<Event> iter = mEvents.descendingIterator();
113        while (iter.hasNext() && count < limit) {
114            Event ev = iter.next();
115            if (userId != UserHandle.USER_ALL && userId != ev.userId) {
116                continue;
117            }
118
119            writer.print(linePrefix);
120            writer.printf("#%-2d %s %s: ", count, formatElapsed(ev.elapsedTimestamp),
121                    dumpType(ev.type));
122            if (userId == UserHandle.USER_ALL) {
123                writer.print("user="); writer.print(ev.userId); writer.print(", ");
124            }
125            writer.print("agent=");
126            if (duplicateSimpleNames) {
127                writer.print(ev.agent.flattenToShortString());
128            } else {
129                writer.print(getSimpleName(ev.agent));
130            }
131            switch (ev.type) {
132                case TYPE_GRANT_TRUST:
133                    writer.printf(", message=\"%s\", duration=%s, flags=%s",
134                            ev.message, formatDuration(ev.duration), dumpGrantFlags(ev.flags));
135                    break;
136                case TYPE_MANAGING_TRUST:
137                    writer.printf(", managingTrust=" + ev.managingTrust);
138                    break;
139                default:
140            }
141            writer.println();
142            count++;
143        }
144    }
145
146    public static String formatDuration(long duration) {
147        StringBuilder sb = new StringBuilder();
148        TimeUtils.formatDuration(duration, sb);
149        return sb.toString();
150    }
151
152    private static String formatElapsed(long elapsed) {
153        long delta = elapsed - SystemClock.elapsedRealtime();
154        long wallTime = delta + System.currentTimeMillis();
155        return TimeUtils.logTimeOfDay(wallTime);
156    }
157
158    /* package */ static String getSimpleName(ComponentName cn) {
159        String name = cn.getClassName();
160        int idx = name.lastIndexOf('.');
161        if (idx < name.length() && idx >= 0) {
162            return name.substring(idx + 1);
163        } else {
164            return name;
165        }
166    }
167
168    private String dumpType(int type) {
169        switch (type) {
170            case TYPE_GRANT_TRUST:
171                return "GrantTrust";
172            case TYPE_REVOKE_TRUST:
173                return "RevokeTrust";
174            case TYPE_TRUST_TIMEOUT:
175                return "TrustTimeout";
176            case TYPE_AGENT_DIED:
177                return "AgentDied";
178            case TYPE_AGENT_CONNECTED:
179                return "AgentConnected";
180            case TYPE_AGENT_STOPPED:
181                return "AgentStopped";
182            case TYPE_MANAGING_TRUST:
183                return "ManagingTrust";
184            default:
185                return "Unknown(" + type + ")";
186        }
187    }
188
189    private String dumpGrantFlags(int flags) {
190        StringBuilder sb = new StringBuilder();
191        if ((flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0) {
192            if (sb.length() != 0) sb.append('|');
193            sb.append("INITIATED_BY_USER");
194        }
195        if ((flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0) {
196            if (sb.length() != 0) sb.append('|');
197            sb.append("DISMISS_KEYGUARD");
198        }
199        if (sb.length() == 0) {
200            sb.append('0');
201        }
202        return sb.toString();
203    }
204}
205