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::am::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 }; 46 47 enum class Temperature : int32_t { 48 kUninitialized = -1, 49 kCold = 1, 50 kWarm = 2, 51 kHot = 3, 52 }; 53 54 Type type{Type::kUninitialized}; 55 int64_t sequence_id{-1}; 56 // kIntentStarted only. 57 std::unique_ptr<IntentProto> intent_proto; 58 // kActivityLaunched only. 59 Temperature temperature{Temperature::kUninitialized}; 60 // kActivityLaunch*. Can be null in kActivityLaunchCancelled. 61 std::unique_ptr<ActivityRecordProto> activity_record_proto; 62 63 AppLaunchEvent() = default; 64 AppLaunchEvent(Type type, 65 int64_t sequence_id, 66 std::unique_ptr<IntentProto> intent_proto = nullptr, 67 Temperature temperature = Temperature::kUninitialized, 68 std::unique_ptr<ActivityRecordProto> activity_record_proto = nullptr) typeAppLaunchEvent69 : type(type), 70 sequence_id(sequence_id), 71 intent_proto(std::move(intent_proto)), 72 temperature(temperature), 73 activity_record_proto(std::move(activity_record_proto)) { 74 } 75 readFromParcelAppLaunchEvent76 ::android::status_t readFromParcel(const android::Parcel* parcel) override { 77 78 # define PARCEL_READ_OR_RETURN(function, ...) \ 79 if (::android::status_t res = function(__VA_ARGS__); res != ::android::NO_ERROR) { \ 80 LOG(ERROR) << "AppLaunchEvent::readFromParcel failed"; \ 81 return res; \ 82 } 83 84 int32_t type_int; 85 PARCEL_READ_OR_RETURN(parcel->readInt32, &type_int); 86 type = static_cast<Type>(type_int); 87 88 LOG(VERBOSE) << "AppLaunchEvent::readFromParcel (type=" << type_int << ")"; 89 90 PARCEL_READ_OR_RETURN(parcel->readInt64, &sequence_id); 91 92 switch (type) { 93 case Type::kIntentStarted: 94 PARCEL_READ_OR_RETURN(readIntent, parcel); 95 break; 96 case Type::kIntentFailed: 97 // No extra arguments. 98 break; 99 case Type::kActivityLaunched: { 100 PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel); 101 int32_t temperature_int; 102 PARCEL_READ_OR_RETURN(parcel->readInt32, &temperature_int); 103 temperature = static_cast<Temperature>(temperature_int); 104 break; 105 } 106 case Type::kActivityLaunchFinished: 107 PARCEL_READ_OR_RETURN(readActivityRecordProto, parcel); 108 break; 109 case Type::kActivityLaunchCancelled: 110 PARCEL_READ_OR_RETURN(readActivityRecordProtoNullable, parcel); 111 break; 112 default: 113 return android::BAD_VALUE; 114 } 115 # undef PARCEL_READ_OR_RETURN 116 117 return ::android::NO_ERROR; 118 119 // TODO: std::variant + protobuf implementation in AutoParcelable. 120 } 121 122 #define PARCEL_WRITE_OR_RETURN(function, ...) \ 123 if (::android::status_t res = function(__VA_ARGS__); res != ::android::NO_ERROR) { \ 124 return res; \ 125 } 126 writeToParcelAppLaunchEvent127 ::android::status_t writeToParcel(android::Parcel* parcel) const override { 128 PARCEL_WRITE_OR_RETURN(parcel->writeInt32, static_cast<int32_t>(type)); 129 PARCEL_WRITE_OR_RETURN(parcel->writeInt64, sequence_id); 130 131 switch (type) { 132 case Type::kIntentStarted: 133 PARCEL_WRITE_OR_RETURN(writeIntent, parcel); 134 break; 135 case Type::kIntentFailed: 136 // No extra arguments. 137 break; 138 case Type::kActivityLaunched: 139 PARCEL_WRITE_OR_RETURN(writeActivityRecordProto, parcel); 140 PARCEL_WRITE_OR_RETURN(parcel->writeInt32, static_cast<int32_t>(temperature)); 141 break; 142 case Type::kActivityLaunchFinished: 143 PARCEL_WRITE_OR_RETURN(writeActivityRecordProto, parcel); 144 break; 145 case Type::kActivityLaunchCancelled: 146 PARCEL_WRITE_OR_RETURN(writeActivityRecordProtoNullable, parcel); 147 break; 148 default: 149 DCHECK(false) << "attempted to write an uninitialized AppLaunchEvent to Parcel"; 150 return android::BAD_VALUE; 151 } 152 153 #undef PARCEL_WRITE_OR_RETURN 154 155 return android::NO_ERROR; 156 } 157 158 private: 159 // Using 'unique_ptr' here because protobufs don't have a move constructor. Is there 160 // a better way that is cheap to pass them around? 161 template <typename T> 162 static expected<std::unique_ptr<T>, ::android::status_t> ReadProtoAppLaunchEvent163 ReadProto(const android::Parcel* parcel) { 164 DCHECK(parcel != nullptr); 165 166 ::android::status_t res; 167 168 std::vector<uint8_t> byte_vector; 169 if ((res = parcel->readByteVector(/*out*/&byte_vector)) != ::android::NO_ERROR) { 170 return unexpected(res); 171 } 172 // TODO: we may want to do this without an extra copy, by parsing 173 // the protobuf directly out of the parcel. 174 175 const uint8_t* data = byte_vector.data(); 176 const size_t size = byte_vector.size(); 177 178 std::unique_ptr<T> proto_ptr{new T{}}; 179 180 if (!proto_ptr) { 181 return unexpected(::android::NO_MEMORY); 182 } 183 184 if (!proto_ptr->ParseFromArray(data, size)) { 185 return unexpected(::android::BAD_VALUE); 186 } 187 188 return proto_ptr; 189 } 190 191 template <typename T> 192 static expected<std::unique_ptr<T>, ::android::status_t> ReadNullableProtoAppLaunchEvent193 ReadNullableProto(const android::Parcel* parcel) { 194 DCHECK(parcel != nullptr); 195 196 bool value; 197 198 ::android::status_t res; 199 res = parcel->readBool(/*out*/&value); 200 201 if (res != ::android::NO_ERROR) { 202 return unexpected(res); 203 } 204 205 if (!value) { 206 return std::unique_ptr<T>{nullptr}; 207 } 208 209 return ReadProto<T>(parcel); 210 } 211 212 template <typename T> 213 static ::android::status_t WriteProtoAppLaunchEvent214 WriteProto(android::Parcel* parcel, const std::unique_ptr<T>& proto) { 215 DCHECK(parcel != nullptr); 216 DCHECK(proto != nullptr); 217 218 std::vector<uint8_t> byte_vector; 219 { 220 const int serialized_size = proto->ByteSize(); 221 byte_vector.resize(serialized_size); 222 if (!proto->SerializeToArray(byte_vector.data(), serialized_size)) { 223 return ::android::BAD_VALUE; 224 } 225 } 226 227 ::android::status_t res; 228 if ((res = parcel->writeByteVector(/*in*/byte_vector)) != ::android::NO_ERROR) { 229 return res; 230 } 231 232 return ::android::NO_ERROR; 233 } 234 235 template <typename T> 236 static ::android::status_t WriteNullableProtoAppLaunchEvent237 WriteNullableProto(android::Parcel* parcel, const std::unique_ptr<T>& maybe_proto) { 238 bool value = (maybe_proto != nullptr); 239 240 ::android::status_t res; 241 res = parcel->writeBool(value); 242 243 if (res != ::android::NO_ERROR) { 244 return res; 245 } 246 247 if (!value) { 248 return ::android::NO_ERROR; 249 } 250 251 return WriteProto<T>(parcel, maybe_proto); 252 } 253 readIntentAppLaunchEvent254 android::status_t readIntent(const android::Parcel* parcel) { 255 expected<std::unique_ptr<IntentProto>, ::android::status_t> maybe_intent = 256 ReadProto<IntentProto>(parcel); 257 258 if (maybe_intent) { 259 intent_proto = std::move(maybe_intent.value()); 260 return ::android::NO_ERROR; 261 } else { 262 return maybe_intent.error(); 263 } 264 } 265 readActivityRecordProtoAppLaunchEvent266 android::status_t readActivityRecordProto(const android::Parcel* parcel) { 267 expected<std::unique_ptr<ActivityRecordProto>, ::android::status_t> maybe_record = 268 ReadProto<ActivityRecordProto>(parcel); 269 270 if (maybe_record) { 271 activity_record_proto = std::move(maybe_record.value()); 272 return ::android::NO_ERROR; 273 } else { 274 return maybe_record.error(); 275 } 276 } 277 readActivityRecordProtoNullableAppLaunchEvent278 android::status_t readActivityRecordProtoNullable(const android::Parcel* parcel) { 279 expected<std::unique_ptr<ActivityRecordProto>, ::android::status_t> maybe_record = 280 ReadNullableProto<ActivityRecordProto>(parcel); 281 282 if (maybe_record) { 283 activity_record_proto = std::move(maybe_record.value()); 284 return ::android::NO_ERROR; 285 } else { 286 return maybe_record.error(); 287 } 288 } 289 writeIntentAppLaunchEvent290 android::status_t writeIntent(android::Parcel* parcel) const { 291 return WriteProto<IntentProto>(parcel, intent_proto); 292 } 293 writeActivityRecordProtoAppLaunchEvent294 android::status_t writeActivityRecordProto(android::Parcel* parcel) const { 295 return WriteProto<ActivityRecordProto>(parcel, activity_record_proto); 296 } 297 writeActivityRecordProtoNullableAppLaunchEvent298 android::status_t writeActivityRecordProtoNullable(android::Parcel* parcel) const { 299 return WriteNullableProto<ActivityRecordProto>(parcel, activity_record_proto); 300 } 301 }; 302 303 inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent::Type& type) { 304 switch (type) { 305 case AppLaunchEvent::Type::kUninitialized: 306 os << "kUninitialized"; 307 break; 308 case AppLaunchEvent::Type::kIntentStarted: 309 os << "kIntentStarted"; 310 break; 311 case AppLaunchEvent::Type::kIntentFailed: 312 os << "kIntentFailed"; 313 break; 314 case AppLaunchEvent::Type::kActivityLaunched: 315 os << "kActivityLaunched"; 316 break; 317 case AppLaunchEvent::Type::kActivityLaunchCancelled: 318 os << "kActivityLaunchCancelled"; 319 break; 320 case AppLaunchEvent::Type::kActivityLaunchFinished: 321 os << "kActivityLaunchFinished"; 322 break; 323 default: 324 os << "(unknown)"; 325 } 326 return os; 327 } 328 329 inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent::Temperature& type) { 330 switch (type) { 331 case AppLaunchEvent::Temperature::kUninitialized: 332 os << "kUninitialized"; 333 break; 334 case AppLaunchEvent::Temperature::kCold: 335 os << "kCold"; 336 break; 337 case AppLaunchEvent::Temperature::kWarm: 338 os << "kWarm"; 339 break; 340 case AppLaunchEvent::Temperature::kHot: 341 os << "kHot"; 342 break; 343 default: 344 os << "(unknown)"; 345 } 346 return os; 347 } 348 349 inline std::ostream& operator<<(std::ostream& os, const AppLaunchEvent& e) { 350 os << "AppLaunchEvent{"; 351 os << "type=" << e.type << ","; 352 os << "sequence_id=" << e.sequence_id << ","; 353 354 os << "intent_proto="; 355 if (e.intent_proto == nullptr) { 356 os << "(nullptr)"; 357 } else { 358 os << "(action=" << e.intent_proto->action() << ","; 359 os << "component="; 360 if (e.intent_proto->has_component()) { 361 // $package/$class_name 362 os << e.intent_proto->component().package_name() << "/" 363 << e.intent_proto->component().class_name(); 364 } else { 365 os << "(no component)"; 366 } 367 os << ")"; 368 } 369 os << ","; 370 371 os << "temperature=" << e.temperature << ","; 372 os << ","; 373 374 os << "activity_record_proto="; 375 if (e.activity_record_proto == nullptr) { 376 os << "(nullptr)"; 377 } else { 378 // title or component name. 379 os << "'" << e.activity_record_proto->identifier().title() << "'"; 380 } 381 os << "}"; 382 383 return os; 384 } 385 386 /* 387 IORAP_INTROSPECT_ADAPT_STRUCT(AppLaunchEvent, 388 type, 389 sequence_id, 390 intent_proto, 391 temperature, 392 activity_record_proto); 393 */ 394 395 } // namespace binder 396 } // namespace iorap 397 398 IORAP_JAVA_NAMESPACE_BINDER_TYPEDEF(AppLaunchEvent) 399 400 #endif // IORAP_BINDER_APP_LAUNCH_EVENT_H_ 401