• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &timestamp_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, &timestamp_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, &timestamp_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