1 /* 2 * Copyright (C) 2018 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 #ifndef IORAP_BINDER_APP_LAUNCH_EVENT_H_ 18 #define IORAP_BINDER_APP_LAUNCH_EVENT_H_ 19 20 #include "binder/common.h" 21 #include "common/introspection.h" 22 #include "common/expected.h" 23 24 #include <binder/Parcel.h> 25 #include <binder/Parcelable.h> 26 #include <frameworks/base/core/proto/android/content/intent.pb.h> // IntentProto 27 #include <frameworks/base/core/proto/android/server/activitymanagerservice.pb.h> // ActivityRecord 28 29 namespace iorap { 30 namespace binder { 31 32 // These protos are part of the iorapd binder ABI, alias them for easier usage. 33 using IntentProto = ::android::content::IntentProto; 34 using ActivityRecordProto = ::com::android::server::wm::ActivityRecordProto; 35 36 struct AppLaunchEvent : public ::android::Parcelable { 37 // Index position matters: Keep up-to-date with AppLaunchEvent.java sTypes field. 38 enum class Type : int32_t { 39 kUninitialized = -1, 40 kIntentStarted = 0, 41 kIntentFailed = 1, 42 kActivityLaunched = 2, 43 kActivityLaunchFinished = 3, 44 kActivityLaunchCancelled = 4, 45 kReportFullyDrawn = 5, 46 }; 47 48 enum class Temperature : int32_t { 49 kUninitialized = -1, 50 kCold = 1, 51 kWarm = 2, 52 kHot = 3, 53 }; 54 55 Type type{Type::kUninitialized}; 56 int64_t sequence_id{-1}; 57 // kIntentStarted only. 58 std::unique_ptr<IntentProto> intent_proto; 59 // kActivityLaunched only. 60 Temperature temperature{Temperature::kUninitialized}; 61 // kActivityLaunch*. Can be null in kActivityLaunchCancelled. 62 std::unique_ptr<ActivityRecordProto> activity_record_proto; 63 // kIntentStarted, kActivityLaunchFinished and kReportFullyDrawn only. 64 int64_t timestamp_nanos{-1}; 65 66 AppLaunchEvent() = default; 67 AppLaunchEvent(Type type, 68 int64_t sequence_id, 69 std::unique_ptr<IntentProto> intent_proto = nullptr, 70 Temperature temperature = Temperature::kUninitialized, 71 std::unique_ptr<ActivityRecordProto> activity_record_proto = nullptr, 72 int64_t timestamp_nanos = -1) typeAppLaunchEvent73 : type(type), 74 sequence_id(sequence_id), 75 intent_proto(std::move(intent_proto)), 76 temperature(temperature), 77 activity_record_proto(std::move(activity_record_proto)), 78 timestamp_nanos(timestamp_nanos) { 79 } 80 AppLaunchEventAppLaunchEvent81 AppLaunchEvent(const AppLaunchEvent& other) { 82 *this = other; 83 } 84 85 AppLaunchEvent& operator=(const AppLaunchEvent& other) { 86 if (&other == this) { 87 return *this; 88 } 89 90 type = other.type; 91 sequence_id = other.sequence_id; 92 if (other.intent_proto != nullptr) { 93 intent_proto.reset(new IntentProto(*other.intent_proto)); 94 } 95 temperature = other.temperature; 96 if (other.activity_record_proto != nullptr) { 97 activity_record_proto.reset(new ActivityRecordProto(*other.activity_record_proto)); 98 } 99 timestamp_nanos = other.timestamp_nanos; 100 101 return *this; 102 } 103 readFromParcelAppLaunchEvent104 ::android::status_t readFromParcel(const android::Parcel* parcel) override { 105 106 # define PARCEL_READ_OR_RETURN(function, ...) \ 107 if (::android::status_t res = function(__VA_ARGS__); res != ::android::NO_ERROR) { \ 108 LOG(ERROR) << "AppLaunchEvent::readFromParcel failed"; \ 109 return res; \ 110 } 111 112 int32_t type_int; 113 PARCEL_READ_OR_RETURN(parcel->readInt32, &type_int); 114 type = static_cast<Type>(type_int); 115 116 LOG(VERBOSE) << "AppLaunchEvent::readFromParcel (type=" << type_int << ")"; 117 118 PARCEL_READ_OR_RETURN(parcel->readInt64, &sequence_id); 119 120 switch (type) { 121 case Type::kIntentStarted: 122 PARCEL_READ_OR_RETURN(readIntent, parcel); 123 PARCEL_READ_OR_RETURN(parcel->readInt64, ×tamp_nanos); 124 break; 125 case Type::kIntentFailed: 126 // No extra arguments. 127 break; 128 case Type::kActivityLaunched: { 129 PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel); 130 int32_t temperature_int; 131 PARCEL_READ_OR_RETURN(parcel->readInt32, &temperature_int); 132 temperature = static_cast<Temperature>(temperature_int); 133 break; 134 } 135 case Type::kActivityLaunchFinished: 136 PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel); 137 PARCEL_READ_OR_RETURN(parcel->readInt64, ×tamp_nanos); 138 break; 139 case Type::kActivityLaunchCancelled: 140 PARCEL_READ_OR_RETURN(readActivityRecordProtoNullable, parcel); 141 break; 142 case Type::kReportFullyDrawn: 143 PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel); 144 PARCEL_READ_OR_RETURN(parcel->readInt64, ×tamp_nanos); 145 break; 146 default: 147 return android::BAD_VALUE; 148 } 149 # undef PARCEL_READ_OR_RETURN 150 151 return ::android::NO_ERROR; 152 153 // TODO: std::variant + protobuf implementation in AutoParcelable. 154 } 155 156 #define PARCEL_WRITE_OR_RETURN(function, ...) \ 157 if (::android::status_t res = function(__VA_ARGS__); res != ::android::NO_ERROR) { \ 158 return res; \ 159 } 160 writeToParcelAppLaunchEvent161 ::android::status_t writeToParcel(android::Parcel* parcel) const override { 162 PARCEL_WRITE_OR_RETURN(parcel->writeInt32, static_cast<int32_t>(type)); 163 PARCEL_WRITE_OR_RETURN(parcel->writeInt64, sequence_id); 164 165 switch (type) { 166 case Type::kIntentStarted: 167 PARCEL_WRITE_OR_RETURN(writeIntent, parcel); 168 PARCEL_WRITE_OR_RETURN(parcel->writeInt64, timestamp_nanos); 169 break; 170 case Type::kIntentFailed: 171 // No extra arguments. 172 break; 173 case Type::kActivityLaunched: 174 PARCEL_WRITE_OR_RETURN(writeActivityRecordProto, parcel); 175 PARCEL_WRITE_OR_RETURN(parcel->writeInt32, static_cast<int32_t>(temperature)); 176 break; 177 case Type::kActivityLaunchFinished: 178 PARCEL_WRITE_OR_RETURN(writeActivityRecordProto, parcel); 179 PARCEL_WRITE_OR_RETURN(parcel->writeInt64, timestamp_nanos); 180 break; 181 case Type::kActivityLaunchCancelled: 182 PARCEL_WRITE_OR_RETURN(writeActivityRecordProtoNullable, parcel); 183 break; 184 case Type::kReportFullyDrawn: 185 PARCEL_WRITE_OR_RETURN(writeActivityRecordProtoNullable, parcel); 186 PARCEL_WRITE_OR_RETURN(parcel->writeInt64, timestamp_nanos); 187 break; 188 default: 189 DCHECK(false) << "attempted to write an uninitialized AppLaunchEvent to Parcel"; 190 return android::BAD_VALUE; 191 } 192 193 #undef PARCEL_WRITE_OR_RETURN 194 195 return android::NO_ERROR; 196 } 197 198 private: 199 // Using 'unique_ptr' here because protobufs don't have a move constructor. Is there 200 // a better way that is cheap to pass them around? 201 template <typename T> 202 static expected<std::unique_ptr<T>, ::android::status_t> ReadProtoAppLaunchEvent203 ReadProto(const android::Parcel* parcel) { 204 DCHECK(parcel != nullptr); 205 206 ::android::status_t res; 207 208 std::vector<uint8_t> byte_vector; 209 if ((res = parcel->readByteVector(/*out*/&byte_vector)) != ::android::NO_ERROR) { 210 return unexpected(res); 211 } 212 // TODO: we may want to do this without an extra copy, by parsing 213 // the protobuf directly out of the parcel. 214 215 const uint8_t* data = byte_vector.data(); 216 const size_t size = byte_vector.size(); 217 218 std::unique_ptr<T> proto_ptr{new T{}}; 219 220 if (!proto_ptr) { 221 return unexpected(::android::NO_MEMORY); 222 } 223 224 if (!proto_ptr->ParseFromArray(data, size)) { 225 return unexpected(::android::BAD_VALUE); 226 } 227 228 return proto_ptr; 229 } 230 231 template <typename T> 232 static expected<std::unique_ptr<T>, ::android::status_t> ReadNullableProtoAppLaunchEvent233 ReadNullableProto(const android::Parcel* parcel) { 234 DCHECK(parcel != nullptr); 235 236 bool value; 237 238 ::android::status_t res; 239 res = parcel->readBool(/*out*/&value); 240 241 if (res != ::android::NO_ERROR) { 242 return unexpected(res); 243 } 244 245 if (!value) { 246 return std::unique_ptr<T>{nullptr}; 247 } 248 249 return ReadProto<T>(parcel); 250 } 251 252 template <typename T> 253 static ::android::status_t WriteProtoAppLaunchEvent254 WriteProto(android::Parcel* parcel, const std::unique_ptr<T>& proto) { 255 DCHECK(parcel != nullptr); 256 DCHECK(proto != nullptr); 257 258 std::vector<uint8_t> byte_vector; 259 { 260 const int serialized_size = proto->ByteSize(); 261 byte_vector.resize(serialized_size); 262 if (!proto->SerializeToArray(byte_vector.data(), serialized_size)) { 263 return ::android::BAD_VALUE; 264 } 265 } 266 267 ::android::status_t res; 268 if ((res = parcel->writeByteVector(/*in*/byte_vector)) != ::android::NO_ERROR) { 269 return res; 270 } 271 272 return ::android::NO_ERROR; 273 } 274 275 template <typename T> 276 static ::android::status_t WriteNullableProtoAppLaunchEvent277 WriteNullableProto(android::Parcel* parcel, const std::unique_ptr<T>& maybe_proto) { 278 bool value = (maybe_proto != nullptr); 279 280 ::android::status_t res; 281 res = parcel->writeBool(value); 282 283 if (res != ::android::NO_ERROR) { 284 return res; 285 } 286 287 if (!value) { 288 return ::android::NO_ERROR; 289 } 290 291 return WriteProto<T>(parcel, maybe_proto); 292 } 293 readIntentAppLaunchEvent294 android::status_t readIntent(const android::Parcel* parcel) { 295 expected<std::unique_ptr<IntentProto>, ::android::status_t> maybe_intent = 296 ReadProto<IntentProto>(parcel); 297 298 if (maybe_intent) { 299 intent_proto = std::move(maybe_intent.value()); 300 return ::android::NO_ERROR; 301 } else { 302 return maybe_intent.error(); 303 } 304 } 305 readActivityRecordProtoAppLaunchEvent306 android::status_t readActivityRecordProto(const android::Parcel* parcel) { 307 expected<std::unique_ptr<ActivityRecordProto>, ::android::status_t> maybe_record = 308 ReadProto<ActivityRecordProto>(parcel); 309 310 if (maybe_record) { 311 activity_record_proto = std::move(maybe_record.value()); 312 return ::android::NO_ERROR; 313 } else { 314 return maybe_record.error(); 315 } 316 } 317 readActivityRecordProtoNullableAppLaunchEvent318 android::status_t readActivityRecordProtoNullable(const android::Parcel* parcel) { 319 expected<std::unique_ptr<ActivityRecordProto>, ::android::status_t> maybe_record = 320 ReadNullableProto<ActivityRecordProto>(parcel); 321 322 if (maybe_record) { 323 activity_record_proto = std::move(maybe_record.value()); 324 return ::android::NO_ERROR; 325 } else { 326 return maybe_record.error(); 327 } 328 } 329 writeIntentAppLaunchEvent330 android::status_t writeIntent(android::Parcel* parcel) const { 331 return WriteProto<IntentProto>(parcel, intent_proto); 332 } 333 writeActivityRecordProtoAppLaunchEvent334 android::status_t writeActivityRecordProto(android::Parcel* parcel) const { 335 return WriteProto<ActivityRecordProto>(parcel, activity_record_proto); 336 } 337 writeActivityRecordProtoNullableAppLaunchEvent338 android::status_t writeActivityRecordProtoNullable(android::Parcel* parcel) const { 339 return WriteNullableProto<ActivityRecordProto>(parcel, activity_record_proto); 340 } 341 }; 342 343 inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent::Type& type) { 344 switch (type) { 345 case AppLaunchEvent::Type::kUninitialized: 346 os << "kUninitialized"; 347 break; 348 case AppLaunchEvent::Type::kIntentStarted: 349 os << "kIntentStarted"; 350 break; 351 case AppLaunchEvent::Type::kIntentFailed: 352 os << "kIntentFailed"; 353 break; 354 case AppLaunchEvent::Type::kActivityLaunched: 355 os << "kActivityLaunched"; 356 break; 357 case AppLaunchEvent::Type::kActivityLaunchCancelled: 358 os << "kActivityLaunchCancelled"; 359 break; 360 case AppLaunchEvent::Type::kActivityLaunchFinished: 361 os << "kActivityLaunchFinished"; 362 break; 363 case AppLaunchEvent::Type::kReportFullyDrawn: 364 os << "kReportFullyDrawn"; 365 break; 366 default: 367 os << "(unknown)"; 368 } 369 return os; 370 } 371 372 inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent::Temperature& type) { 373 switch (type) { 374 case AppLaunchEvent::Temperature::kUninitialized: 375 os << "kUninitialized"; 376 break; 377 case AppLaunchEvent::Temperature::kCold: 378 os << "kCold"; 379 break; 380 case AppLaunchEvent::Temperature::kWarm: 381 os << "kWarm"; 382 break; 383 case AppLaunchEvent::Temperature::kHot: 384 os << "kHot"; 385 break; 386 default: 387 os << "(unknown)"; 388 } 389 return os; 390 } 391 392 inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent& e) { 393 os << "AppLaunchEvent{"; 394 os << "type=" << e.type << ","; 395 os << "sequence_id=" << e.sequence_id << ","; 396 397 os << "intent_proto="; 398 if (e.intent_proto == nullptr) { 399 os << "(nullptr)"; 400 } else { 401 os << "(action=" << e.intent_proto->action() << ","; 402 os << "component="; 403 if (e.intent_proto->has_component()) { 404 // $package/$class_name 405 os << e.intent_proto->component().package_name() << "/" 406 << e.intent_proto->component().class_name(); 407 } else { 408 os << "(no component)"; 409 } 410 os << ")"; 411 } 412 os << ","; 413 414 os << "temperature=" << e.temperature << ","; 415 os << ","; 416 417 os << "activity_record_proto="; 418 if (e.activity_record_proto == nullptr) { 419 os << "(nullptr)"; 420 } else { 421 // title or component name. 422 os << "'" << e.activity_record_proto->identifier().title() << "'"; 423 } 424 os << ","; 425 426 os << "timestamp_nanos=" << e.timestamp_nanos << ","; 427 os << ","; 428 429 os << "}"; 430 431 return os; 432 } 433 434 /* 435 IORAP_INTROSPECT_ADAPT_STRUCT(AppLaunchEvent, 436 type, 437 sequence_id, 438 intent_proto, 439 temperature, 440 activity_record_proto); 441 */ 442 443 } // namespace binder 444 } // namespace iorap 445 446 IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(AppLaunchEvent) 447 448 #endif // IORAP_BINDER_APP_LAUNCH_EVENT_H_ 449