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