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    private static final int TYPE_POLICY_CHANGED = 7;
41
42    private static final int HISTORY_LIMIT = 200;
43
44    private static class Event {
45        final int type;
46        final int userId;
47        final ComponentName agent;
48        final long elapsedTimestamp;
49
50        // grantTrust
51        final String message;
52        final long duration;
53        final int flags;
54
55        // managingTrust
56        final boolean managingTrust;
57
58        private Event(int type, int userId, ComponentName agent, String message,
59                long duration, int flags, boolean managingTrust) {
60            this.type = type;
61            this.userId = userId;
62            this.agent = agent;
63            this.elapsedTimestamp = SystemClock.elapsedRealtime();
64            this.message = message;
65            this.duration = duration;
66            this.flags = flags;
67            this.managingTrust = managingTrust;
68        }
69    }
70
71    ArrayDeque<Event> mEvents = new ArrayDeque<Event>();
72
73    public void logGrantTrust(int userId, ComponentName agent, String message,
74            long duration, int flags) {
75        addEvent(new Event(TYPE_GRANT_TRUST, userId, agent, message, duration,
76                flags, false));
77    }
78
79    public void logRevokeTrust(int userId, ComponentName agent) {
80        addEvent(new Event(TYPE_REVOKE_TRUST, userId, agent, null, 0, 0, false));
81    }
82
83    public void logTrustTimeout(int userId, ComponentName agent) {
84        addEvent(new Event(TYPE_TRUST_TIMEOUT, userId, agent, null, 0, 0, false));
85    }
86
87    public void logAgentDied(int userId, ComponentName agent) {
88        addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, 0, false));
89    }
90
91    public void logAgentConnected(int userId, ComponentName agent) {
92        addEvent(new Event(TYPE_AGENT_CONNECTED, userId, agent, null, 0, 0, false));
93    }
94
95    public void logAgentStopped(int userId, ComponentName agent) {
96        addEvent(new Event(TYPE_AGENT_STOPPED, userId, agent, null, 0, 0, false));
97    }
98
99    public void logManagingTrust(int userId, ComponentName agent, boolean managing) {
100        addEvent(new Event(TYPE_MANAGING_TRUST, userId, agent, null, 0, 0, managing));
101    }
102
103    public void logDevicePolicyChanged() {
104        addEvent(new Event(TYPE_POLICY_CHANGED, UserHandle.USER_ALL, null, null, 0, 0, false));
105    }
106
107    private void addEvent(Event e) {
108        if (mEvents.size() >= HISTORY_LIMIT) {
109            mEvents.removeFirst();
110        }
111        mEvents.addLast(e);
112    }
113
114    public void dump(PrintWriter writer, int limit, int userId, String linePrefix,
115            boolean duplicateSimpleNames) {
116        int count = 0;
117        Iterator<Event> iter = mEvents.descendingIterator();
118        while (iter.hasNext() && count < limit) {
119            Event ev = iter.next();
120            if (userId != UserHandle.USER_ALL && userId != ev.userId
121                    && ev.userId != UserHandle.USER_ALL) {
122                continue;
123            }
124
125            writer.print(linePrefix);
126            writer.printf("#%-2d %s %s: ", count, formatElapsed(ev.elapsedTimestamp),
127                    dumpType(ev.type));
128            if (userId == UserHandle.USER_ALL) {
129                writer.print("user="); writer.print(ev.userId); writer.print(", ");
130            }
131            if (ev.agent != null) {
132                writer.print("agent=");
133                if (duplicateSimpleNames) {
134                    writer.print(ev.agent.flattenToShortString());
135                } else {
136                    writer.print(getSimpleName(ev.agent));
137                }
138            }
139            switch (ev.type) {
140                case TYPE_GRANT_TRUST:
141                    writer.printf(", message=\"%s\", duration=%s, flags=%s",
142                            ev.message, formatDuration(ev.duration), dumpGrantFlags(ev.flags));
143                    break;
144                case TYPE_MANAGING_TRUST:
145                    writer.printf(", managingTrust=" + ev.managingTrust);
146                    break;
147                default:
148            }
149            writer.println();
150            count++;
151        }
152    }
153
154    public static String formatDuration(long duration) {
155        StringBuilder sb = new StringBuilder();
156        TimeUtils.formatDuration(duration, sb);
157        return sb.toString();
158    }
159
160    private static String formatElapsed(long elapsed) {
161        long delta = elapsed - SystemClock.elapsedRealtime();
162        long wallTime = delta + System.currentTimeMillis();
163        return TimeUtils.logTimeOfDay(wallTime);
164    }
165
166    /* package */ static String getSimpleName(ComponentName cn) {
167        String name = cn.getClassName();
168        int idx = name.lastIndexOf('.');
169        if (idx < name.length() && idx >= 0) {
170            return name.substring(idx + 1);
171        } else {
172            return name;
173        }
174    }
175
176    private String dumpType(int type) {
177        switch (type) {
178            case TYPE_GRANT_TRUST:
179                return "GrantTrust";
180            case TYPE_REVOKE_TRUST:
181                return "RevokeTrust";
182            case TYPE_TRUST_TIMEOUT:
183                return "TrustTimeout";
184            case TYPE_AGENT_DIED:
185                return "AgentDied";
186            case TYPE_AGENT_CONNECTED:
187                return "AgentConnected";
188            case TYPE_AGENT_STOPPED:
189                return "AgentStopped";
190            case TYPE_MANAGING_TRUST:
191                return "ManagingTrust";
192            case TYPE_POLICY_CHANGED:
193                return "DevicePolicyChanged";
194            default:
195                return "Unknown(" + type + ")";
196        }
197    }
198
199    private String dumpGrantFlags(int flags) {
200        StringBuilder sb = new StringBuilder();
201        if ((flags & TrustAgentService.FLAG_GRANT_TRUST_INITIATED_BY_USER) != 0) {
202            if (sb.length() != 0) sb.append('|');
203            sb.append("INITIATED_BY_USER");
204        }
205        if ((flags & TrustAgentService.FLAG_GRANT_TRUST_DISMISS_KEYGUARD) != 0) {
206            if (sb.length() != 0) sb.append('|');
207            sb.append("DISMISS_KEYGUARD");
208        }
209        if (sb.length() == 0) {
210            sb.append('0');
211        }
212        return sb.toString();
213    }
214}
215