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