• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.server.vibrator;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.os.CombinedVibration;
22 import android.os.IBinder;
23 import android.os.VibrationAttributes;
24 import android.util.IndentingPrintWriter;
25 import android.util.proto.ProtoOutputStream;
26 
27 import java.io.PrintWriter;
28 import java.time.Instant;
29 import java.time.ZoneId;
30 import java.time.format.DateTimeFormatter;
31 import java.util.Objects;
32 import java.util.concurrent.atomic.AtomicInteger;
33 
34 /**
35  * Represents a generic vibration session that plays one or more vibration requests.
36  *
37  * <p>This might represent:
38  *
39  * <ol>
40  *     <li>A single {@link CombinedVibration} playback.
41  *     <li>An {@link android.os.ExternalVibration} playback.
42  * </ol>
43  */
44 interface VibrationSession {
45 
46     // Used to generate globally unique session ids.
47     AtomicInteger sNextSessionId = new AtomicInteger(1); // 0 = no callback
48 
nextSessionId()49     static long nextSessionId() {
50         return sNextSessionId.getAndIncrement();
51     }
52 
53     /** Returns the session id. */
getSessionId()54     long getSessionId();
55 
56     /** Returns the session creation time from {@link android.os.SystemClock#uptimeMillis()}. */
getCreateUptimeMillis()57     long getCreateUptimeMillis();
58 
59     /** Return true if vibration session plays a repeating vibration. */
isRepeating()60     boolean isRepeating();
61 
62     /** Returns data about the client app that triggered this vibration session. */
getCallerInfo()63     CallerInfo getCallerInfo();
64 
65     /** Returns the binder token from the client app attached to this vibration session. */
getCallerToken()66     IBinder getCallerToken();
67 
68     /** Returns debug data for logging and metric reports. */
getDebugInfo()69     DebugInfo getDebugInfo();
70 
71     /** Links this session to the app process death, returning false if link failed. */
linkToDeath()72     boolean linkToDeath();
73 
74     /** Removes link to the app process death. */
unlinkToDeath()75     void unlinkToDeath();
76 
77     /** Returns true if this session was requested to end by {@link #requestEnd}. */
wasEndRequested()78     boolean wasEndRequested();
79 
80     /**
81      * Request the end of this session, which might be acted upon asynchronously.
82      *
83      * <p>This is the same as {@link #requestEnd(Status, CallerInfo, boolean)}, with no
84      * {@link CallerInfo} and with {@code immediate} flag set to false.
85      */
requestEnd(@onNull Status status)86     default void requestEnd(@NonNull Status status) {
87         requestEnd(status, /* endedBy= */ null, /* immediate= */ false);
88     }
89 
90     /**
91      * Notify the session end was requested, which might be acted upon asynchronously.
92      *
93      * <p>Only the first end signal will be used to end a session, but subsequent calls with
94      * {@code immediate} flag set to true can still force it to take effect urgently.
95      *
96      * @param status the end status.
97      * @param endedBy the {@link CallerInfo} of the session that requested this session to end.
98      * @param immediate indicates whether cancellation should abort urgently and skip cleanup steps.
99      */
requestEnd(@onNull Status status, @Nullable CallerInfo endedBy, boolean immediate)100     void requestEnd(@NonNull Status status, @Nullable CallerInfo endedBy, boolean immediate);
101 
102     /**
103      * Notify a vibrator has completed the last command during the playback of given vibration.
104      *
105      * <p>This will be called by the vibrator hardware callback indicating the last vibrate call is
106      * complete (e.g. on(), perform(), compose()). This does not mean the vibration is complete,
107      * since its playback might have one or more interactions with the vibrator hardware.
108      */
notifyVibratorCallback(int vibratorId, long vibrationId, long stepId)109     void notifyVibratorCallback(int vibratorId, long vibrationId, long stepId);
110 
111     /**
112      * Notify all synced vibrators have completed the last synchronized command during the playback
113      * of given vibration.
114      *
115      * <p>This will be called by the vibrator manager hardware callback indicating the last
116      * synchronized vibrate call is complete. This does not mean the vibration is complete, since
117      * its playback might have one or more interactions with the vibrator hardware.
118      */
notifySyncedVibratorsCallback(long vibrationId)119     void notifySyncedVibratorsCallback(long vibrationId);
120 
121     /**
122      * Notify vibrator manager have completed the vibration session.
123      *
124      * <p>This will be called by the vibrator manager hardware callback indicating the session
125      * is complete, either because it was ended or cancelled by the service or the vendor.
126      */
notifySessionCallback()127     void notifySessionCallback();
128 
129     /**
130      * Session status with reference to values from vibratormanagerservice.proto for logging.
131      */
132     enum Status {
133         UNKNOWN(VibrationProto.UNKNOWN),
134         RUNNING(VibrationProto.RUNNING),
135         FINISHED(VibrationProto.FINISHED),
136         FINISHED_UNEXPECTED(VibrationProto.FINISHED_UNEXPECTED),
137         FORWARDED_TO_INPUT_DEVICES(VibrationProto.FORWARDED_TO_INPUT_DEVICES),
138         CANCELLED_BINDER_DIED(VibrationProto.CANCELLED_BINDER_DIED),
139         CANCELLED_BY_SCREEN_OFF(VibrationProto.CANCELLED_BY_SCREEN_OFF),
140         CANCELLED_BY_SETTINGS_UPDATE(VibrationProto.CANCELLED_BY_SETTINGS_UPDATE),
141         CANCELLED_BY_USER(VibrationProto.CANCELLED_BY_USER),
142         CANCELLED_BY_FOREGROUND_USER(VibrationProto.CANCELLED_BY_FOREGROUND_USER),
143         CANCELLED_BY_UNKNOWN_REASON(VibrationProto.CANCELLED_BY_UNKNOWN_REASON),
144         CANCELLED_SUPERSEDED(VibrationProto.CANCELLED_SUPERSEDED),
145         CANCELLED_BY_APP_OPS(VibrationProto.CANCELLED_BY_APP_OPS),
146         IGNORED_ERROR_APP_OPS(VibrationProto.IGNORED_ERROR_APP_OPS),
147         IGNORED_ERROR_CANCELLING(VibrationProto.IGNORED_ERROR_CANCELLING),
148         IGNORED_ERROR_SCHEDULING(VibrationProto.IGNORED_ERROR_SCHEDULING),
149         IGNORED_ERROR_TOKEN(VibrationProto.IGNORED_ERROR_TOKEN),
150         IGNORED_APP_OPS(VibrationProto.IGNORED_APP_OPS),
151         IGNORED_BACKGROUND(VibrationProto.IGNORED_BACKGROUND),
152         IGNORED_MISSING_PERMISSION(VibrationProto.IGNORED_MISSING_PERMISSION),
153         IGNORED_UNSUPPORTED(VibrationProto.IGNORED_UNSUPPORTED),
154         IGNORED_FOR_EXTERNAL(VibrationProto.IGNORED_FOR_EXTERNAL),
155         IGNORED_FOR_HIGHER_IMPORTANCE(VibrationProto.IGNORED_FOR_HIGHER_IMPORTANCE),
156         IGNORED_FOR_ONGOING(VibrationProto.IGNORED_FOR_ONGOING),
157         IGNORED_FOR_POWER(VibrationProto.IGNORED_FOR_POWER),
158         IGNORED_FOR_RINGER_MODE(VibrationProto.IGNORED_FOR_RINGER_MODE),
159         IGNORED_FOR_SETTINGS(VibrationProto.IGNORED_FOR_SETTINGS),
160         IGNORED_SUPERSEDED(VibrationProto.IGNORED_SUPERSEDED),
161         IGNORED_FROM_VIRTUAL_DEVICE(VibrationProto.IGNORED_FROM_VIRTUAL_DEVICE),
162         IGNORED_ON_WIRELESS_CHARGER(VibrationProto.IGNORED_ON_WIRELESS_CHARGER);
163 
164         private final int mProtoEnumValue;
165 
Status(int value)166         Status(int value) {
167             mProtoEnumValue = value;
168         }
169 
getProtoEnumValue()170         public int getProtoEnumValue() {
171             return mProtoEnumValue;
172         }
173     }
174 
175     /**
176      * Holds lightweight immutable info on the process that triggered the vibration session.
177      *
178      * <p>This data could potentially be kept in memory for a long time for bugreport dumpsys
179      * operations. It shouldn't hold any references to potentially expensive or resource-linked
180      * objects, such as {@link IBinder}.
181      */
182     final class CallerInfo {
183         public final VibrationAttributes attrs;
184         public final int uid;
185         public final int deviceId;
186         public final String opPkg;
187         public final String reason;
188 
CallerInfo(@onNull VibrationAttributes attrs, int uid, int deviceId, String opPkg, @Nullable String reason)189         CallerInfo(@NonNull VibrationAttributes attrs, int uid, int deviceId, String opPkg,
190                 @Nullable String reason) {
191             Objects.requireNonNull(attrs);
192             this.attrs = attrs;
193             this.uid = uid;
194             this.deviceId = deviceId;
195             this.opPkg = opPkg;
196             this.reason = reason;
197         }
198 
199         @Override
equals(Object o)200         public boolean equals(Object o) {
201             if (this == o) return true;
202             if (!(o instanceof CallerInfo)) return false;
203             CallerInfo that = (CallerInfo) o;
204             return Objects.equals(attrs, that.attrs)
205                     && uid == that.uid
206                     && deviceId == that.deviceId
207                     && Objects.equals(opPkg, that.opPkg)
208                     && Objects.equals(reason, that.reason);
209         }
210 
211         @Override
hashCode()212         public int hashCode() {
213             return Objects.hash(attrs, uid, deviceId, opPkg, reason);
214         }
215 
216         @Override
toString()217         public String toString() {
218             return "CallerInfo{"
219                     + " uid=" + uid
220                     + ", opPkg=" + opPkg
221                     + ", deviceId=" + deviceId
222                     + ", attrs=" + attrs
223                     + ", reason=" + reason
224                     + '}';
225         }
226     }
227 
228     /**
229      * Interface for lightweight debug information about the vibration session for debugging.
230      *
231      * <p>This data could potentially be kept in memory for a long time for bugreport dumpsys
232      * operations. It shouldn't hold any references to potentially expensive or resource-linked
233      * objects, such as {@link IBinder}.
234      */
235     interface DebugInfo {
236 
237         DateTimeFormatter DEBUG_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss.SSS");
238         DateTimeFormatter DEBUG_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(
239                 "MM-dd HH:mm:ss.SSS");
240 
formatTime(long timeInMillis, boolean includeDate)241         static String formatTime(long timeInMillis, boolean includeDate) {
242             return (includeDate ? DEBUG_DATE_TIME_FORMATTER : DEBUG_TIME_FORMATTER)
243                     // Ensure timezone is retrieved at formatting time
244                     .withZone(ZoneId.systemDefault())
245                     .format(Instant.ofEpochMilli(timeInMillis));
246         }
247 
248         /** Return the vibration session status. */
getStatus()249         Status getStatus();
250 
251         /** Returns the session creation time from {@link android.os.SystemClock#uptimeMillis()}. */
getCreateUptimeMillis()252         long getCreateUptimeMillis();
253 
254         /** Returns information about the process that created the session. */
getCallerInfo()255         CallerInfo getCallerInfo();
256 
257         /**
258          * Returns the aggregation key for log records.
259          *
260          * <p>This is used to aggregate similar vibration sessions triggered in quick succession
261          * (e.g. multiple keyboard vibrations when the user is typing).
262          *
263          * <p>This does not need to include data from {@link CallerInfo} or {@link Status}.
264          *
265          * @see GroupedAggregatedLogRecords
266          */
267         @Nullable
getDumpAggregationKey()268         Object getDumpAggregationKey();
269 
270         /** Logs vibration session fields for metric reports. */
logMetrics(VibratorFrameworkStatsLogger statsLogger)271         void logMetrics(VibratorFrameworkStatsLogger statsLogger);
272 
273         /** Write this info into given {@code fieldId} on {@link ProtoOutputStream}. */
dump(ProtoOutputStream proto, long fieldId)274         void dump(ProtoOutputStream proto, long fieldId);
275 
276         /** Write this info into given {@link PrintWriter}. */
dump(IndentingPrintWriter pw)277         void dump(IndentingPrintWriter pw);
278 
279         /**
280          * Write this info in a compact way into given {@link PrintWriter}.
281          *
282          * <p>This is used by dumpsys to log multiple records in single lines that are easy to skim
283          * through by the sorted created time.
284          */
dumpCompact(IndentingPrintWriter pw)285         void dumpCompact(IndentingPrintWriter pw);
286     }
287 }
288