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