1/*
2 * Copyright (C) 2016 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 android.app.admin;
18
19import android.annotation.IntDef;
20import android.os.Parcel;
21import android.os.Parcelable;
22import android.os.SystemProperties;
23import android.util.EventLog.Event;
24
25import java.io.IOException;
26import java.lang.annotation.Retention;
27import java.lang.annotation.RetentionPolicy;
28import java.util.Collection;
29
30/**
31 * Definitions for working with security logs.
32 *
33 * <p>Device owner apps can control the logging with
34 * {@link DevicePolicyManager#setSecurityLoggingEnabled}. When security logs are enabled, device
35 * owner apps receive periodic callbacks from {@link DeviceAdminReceiver#onSecurityLogsAvailable},
36 * at which time new batch of logs can be collected via
37 * {@link DevicePolicyManager#retrieveSecurityLogs}. {@link SecurityEvent} describes the type and
38 * format of security logs being collected.
39 */
40public class SecurityLog {
41
42    private static final String PROPERTY_LOGGING_ENABLED = "persist.logd.security";
43
44    /** @hide */
45    @Retention(RetentionPolicy.SOURCE)
46    @IntDef({TAG_ADB_SHELL_INTERACTIVE, TAG_ADB_SHELL_CMD, TAG_SYNC_RECV_FILE, TAG_SYNC_SEND_FILE,
47        TAG_APP_PROCESS_START, TAG_KEYGUARD_DISMISSED, TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT,
48        TAG_KEYGUARD_SECURED})
49    public @interface SECURITY_LOG_TAG {}
50
51    /**
52     * Indicate that an ADB interactive shell was opened via "adb shell".
53     * There is no extra payload in the log event.
54     */
55    public static final int TAG_ADB_SHELL_INTERACTIVE =
56            SecurityLogTags.SECURITY_ADB_SHELL_INTERACTIVE;
57    /**
58     * Indicate that an shell command was issued over ADB via "adb shell command"
59     * The log entry contains a string data of the shell command, accessible via
60     * {@link SecurityEvent#getData()}
61     */
62    public static final int TAG_ADB_SHELL_CMD = SecurityLogTags.SECURITY_ADB_SHELL_COMMAND;
63    /**
64     * Indicate that a file was pulled from the device via the adb daemon, for example via
65     * "adb pull". The log entry contains a string data of the path of the pulled file,
66     * accessible via {@link SecurityEvent#getData()}
67     */
68    public static final int TAG_SYNC_RECV_FILE = SecurityLogTags.SECURITY_ADB_SYNC_RECV;
69    /**
70     * Indicate that a file was pushed to the device via the adb daemon, for example via
71     * "adb push". The log entry contains a string data of the destination path of the
72     * pushed file, accessible via {@link SecurityEvent#getData()}
73     */
74    public static final int TAG_SYNC_SEND_FILE = SecurityLogTags.SECURITY_ADB_SYNC_SEND;
75    /**
76     * Indicate that an app process was started. The log entry contains the following
77     * information about the process encapsulated in an {@link Object} array, accessible via
78     * {@link SecurityEvent#getData()}:
79     * process name (String), exact start time (long), app Uid (integer), app Pid (integer),
80     * seinfo tag (String), SHA-256 hash of the base APK in hexadecimal (String)
81     */
82    public static final int TAG_APP_PROCESS_START = SecurityLogTags.SECURITY_APP_PROCESS_START;
83    /**
84     * Indicate that keyguard is being dismissed.
85     * There is no extra payload in the log event.
86     */
87    public static final int TAG_KEYGUARD_DISMISSED =
88            SecurityLogTags.SECURITY_KEYGUARD_DISMISSED;
89    /**
90     * Indicate that there has been an authentication attempt to dismiss the keyguard. The log entry
91     * contains the following information about the attempt encapsulated in an {@link Object} array,
92     * accessible via {@link SecurityEvent#getData()}:
93     * attempt result (integer, 1 for successful, 0 for unsuccessful), strength of auth method
94     * (integer, 1 if strong auth method was used, 0 otherwise)
95     */
96    public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT =
97            SecurityLogTags.SECURITY_KEYGUARD_DISMISS_AUTH_ATTEMPT;
98    /**
99     * Indicate that the device has been locked, either by user or by timeout.
100     * There is no extra payload in the log event.
101     */
102    public static final int TAG_KEYGUARD_SECURED = SecurityLogTags.SECURITY_KEYGUARD_SECURED;
103
104    /**
105     * Returns if security logging is enabled. Log producers should only write new logs if this is
106     * true. Under the hood this is the logical AND of whether device owner exists and whether
107     * it enables logging by setting the system property {@link #PROPERTY_LOGGING_ENABLED}.
108     * @hide
109     */
110    public static native boolean isLoggingEnabled();
111
112    /**
113     * @hide
114     */
115    public static void setLoggingEnabledProperty(boolean enabled) {
116        SystemProperties.set(PROPERTY_LOGGING_ENABLED, enabled ? "true" : "false");
117    }
118
119    /**
120     * @hide
121     */
122    public static boolean getLoggingEnabledProperty() {
123        return SystemProperties.getBoolean(PROPERTY_LOGGING_ENABLED, false);
124    }
125
126    /**
127     * A class representing a security event log entry.
128     */
129    public static final class SecurityEvent implements Parcelable {
130        private Event mEvent;
131
132        /** @hide */
133        /*package*/ SecurityEvent(byte[] data) {
134            mEvent = Event.fromBytes(data);
135        }
136
137        /**
138         * Returns the timestamp in nano seconds when this event was logged.
139         */
140        public long getTimeNanos() {
141            return mEvent.getTimeNanos();
142        }
143
144        /**
145         * Returns the tag of this log entry, which specifies entry's semantics.
146         * Could be one of {@link SecurityLog#TAG_SYNC_RECV_FILE},
147         * {@link SecurityLog#TAG_SYNC_SEND_FILE}, {@link SecurityLog#TAG_ADB_SHELL_CMD},
148         * {@link SecurityLog#TAG_ADB_SHELL_INTERACTIVE}, {@link SecurityLog#TAG_APP_PROCESS_START},
149         * {@link SecurityLog#TAG_KEYGUARD_DISMISSED}, {@link SecurityLog#TAG_KEYGUARD_SECURED},
150         * {@link SecurityLog#TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT}.
151         */
152        public @SECURITY_LOG_TAG int getTag() {
153            return mEvent.getTag();
154        }
155
156        /**
157         * Returns the payload contained in this log entry or {@code null} if there is no payload.
158         */
159        public Object getData() {
160            return mEvent.getData();
161        }
162
163        @Override
164        public int describeContents() {
165            return 0;
166        }
167
168        @Override
169        public void writeToParcel(Parcel dest, int flags) {
170            dest.writeByteArray(mEvent.getBytes());
171        }
172
173        public static final Parcelable.Creator<SecurityEvent> CREATOR =
174                new Parcelable.Creator<SecurityEvent>() {
175            @Override
176            public SecurityEvent createFromParcel(Parcel source) {
177                return new SecurityEvent(source.createByteArray());
178            }
179
180            @Override
181            public SecurityEvent[] newArray(int size) {
182                return new SecurityEvent[size];
183            }
184        };
185
186        /**
187         * @hide
188         */
189        @Override
190        public boolean equals(Object o) {
191            if (this == o) return true;
192            if (o == null || getClass() != o.getClass()) return false;
193            SecurityEvent other = (SecurityEvent) o;
194            return mEvent.equals(other.mEvent);
195        }
196
197        /**
198         * @hide
199         */
200        @Override
201        public int hashCode() {
202            return mEvent.hashCode();
203        }
204    }
205    /**
206     * Retrieve all security logs and return immediately.
207     * @hide
208     */
209    public static native void readEvents(Collection<SecurityEvent> output) throws IOException;
210
211    /**
212     * Retrieve all security logs since the given timestamp in nanoseconds and return immediately.
213     * @hide
214     */
215    public static native void readEventsSince(long timestamp, Collection<SecurityEvent> output)
216            throws IOException;
217
218    /**
219     * Retrieve all security logs before the last reboot. May return corrupted data due to
220     * unreliable pstore.
221     * @hide
222     */
223    public static native void readPreviousEvents(Collection<SecurityEvent> output)
224            throws IOException;
225
226    /**
227     * Retrieve all security logs whose timestamp (in nanosceonds) is equal to or greater than the
228     * given timestamp. This method will block until either the last log earlier than the given
229     * timestamp is about to be pruned, or after a 2-hour timeout has passed.
230     * @hide
231     */
232    public static native void readEventsOnWrapping(long timestamp, Collection<SecurityEvent> output)
233            throws IOException;
234
235    /**
236     * Write a log entry to the underlying storage, with a string payload.
237     * @hide
238     */
239    public static native int writeEvent(int tag, String str);
240
241    /**
242     * Write a log entry to the underlying storage, with several payloads.
243     * Supported types of payload are: integer, long, float, string plus array of supported types.
244     * @hide
245     */
246    public static native int writeEvent(int tag, Object... payloads);
247}
248