1 /*
2  * Copyright (C) 2020 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 
17 package com.android.eventlib;
18 
19 import android.os.UserHandle;
20 
21 import com.android.bedstead.nene.users.UserReference;
22 import com.android.queryable.Queryable;
23 import com.android.queryable.queries.Query;
24 
25 import java.util.ArrayList;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Set;
29 import java.util.function.Function;
30 
31 /**
32  * Interface to provide additional restrictions on an {@link Event} query.
33  */
34 public abstract class EventLogsQuery<E extends Event, F extends EventLogsQuery>
35         extends EventLogs<E> implements Queryable {
36     private final Class<E> mEventClass;
37     private final String mPackageName;
38     private final transient Set<Function<E, Boolean>> mFilters = new HashSet<>();
39     private transient UserHandle mUserHandle = null; // null is default, meaning current user
40 
EventLogsQuery(Class<E> eventClass, String packageName)41     protected EventLogsQuery(Class<E> eventClass, String packageName) {
42         if (eventClass == null || packageName == null) {
43             throw new NullPointerException();
44         }
45         mQuerier = new RemoteEventQuerier<>(packageName, this);
46         mEventClass = eventClass;
47         mPackageName = packageName;
48     }
49 
50     /** Get the package name being filtered for. */
getPackageName()51     protected String getPackageName() {
52         return mPackageName;
53     }
54 
eventClass()55     protected Class<E> eventClass() {
56         return mEventClass;
57     }
58 
59     private final transient EventQuerier<E> mQuerier;
60 
61     @Override
getQuerier()62     protected EventQuerier<E> getQuerier() {
63         return mQuerier;
64     }
65 
66     /** Apply a lambda filter to the results. */
filter(Function<E, Boolean> filter)67     public F filter(Function<E, Boolean> filter) {
68         mFilters.add(filter);
69         return (F) this;
70     }
71 
72     /**
73      * Returns true if {@code E} matches custom and default filters for this {@link Event} subclass.
74      */
filterAll(E event)75     protected final boolean filterAll(E event) {
76         if (mFilters != null) {
77             // Filters will be null when called remotely
78             for (Function<E, Boolean> filter : mFilters) {
79                 if (!filter.apply(event)) {
80                     return false;
81                 }
82             }
83         }
84         return filter(event);
85     }
86 
87     /** Returns true if {@code E} matches the custom filters for this {@link Event} subclass. */
filter(E event)88     protected abstract boolean filter(E event);
89 
90     /** Query a package running on another user. */
onUser(UserHandle userHandle)91     public F onUser(UserHandle userHandle) {
92         if (userHandle == null) {
93             throw new NullPointerException();
94         }
95         mUserHandle = userHandle;
96         return (F) this;
97     }
98 
99     /** Query a package running on another user. */
onUser(UserReference userReference)100     public F onUser(UserReference userReference) {
101         return onUser(userReference.userHandle());
102     }
103 
getUserHandle()104     UserHandle getUserHandle() {
105         return mUserHandle;
106     }
107 
108     @Override
isEmptyQuery()109     public boolean isEmptyQuery() {
110         // TODO(276741712): This is not currently used - but should be implemented correctly for
111         //  subclasses
112         return true;
113     }
114 
115     public static class ToStringBuilder {
116 
117         private final List<String> mFields = new ArrayList<>();
118         private final int mNumberOfCustomFilters;
119 
ToStringBuilder(String eventType, EventLogsQuery<?, ?> query)120         private ToStringBuilder(String eventType, EventLogsQuery<?, ?> query) {
121             mFields.add("type=" + eventType);
122             mFields.add("packageName=" + query.mPackageName);
123             if (query.mUserHandle != null) {
124                 mFields.add("user=" + query.mUserHandle);
125             }
126             mNumberOfCustomFilters = query.mFilters.size();
127         }
128 
field(String fieldName, Query<?> query)129         public ToStringBuilder field(String fieldName, Query<?> query) {
130             mFields.add(query.describeQuery(fieldName));
131             return this;
132         }
133 
134         @Override
toString()135         public String toString() {
136             if (mNumberOfCustomFilters > 0) {
137                 mFields.add(mNumberOfCustomFilters + " custom filters");
138             }
139             return "{" + Queryable.joinQueryStrings(mFields) + "}";
140         }
141     }
142 
toStringBuilder( Class<N> eventClass, EventLogsQuery<N, ?> query)143     public <N extends Event> ToStringBuilder toStringBuilder(
144             Class<N> eventClass, EventLogsQuery<N, ?> query) {
145         return new ToStringBuilder(eventClass.getSimpleName(), query);
146     }
147 
148     @Override
toString()149     public String toString() {
150         return describeQuery("Query");
151     }
152 }
153