• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef ANDROID_PDX_SERVICE_H_
2 #define ANDROID_PDX_SERVICE_H_
3 
4 #include <errno.h>
5 #include <log/log.h>
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 
10 #include <algorithm>
11 #include <memory>
12 #include <mutex>
13 #include <string>
14 #include <unordered_map>
15 #include <vector>
16 
17 #include "pdx/channel_handle.h"
18 #include "pdx/file_handle.h"
19 #include "pdx/message_reader.h"
20 #include "pdx/message_writer.h"
21 #include "pdx/service_endpoint.h"
22 
23 namespace android {
24 namespace pdx {
25 
26 class Service;
27 
28 namespace opcodes {
29 
30 /*
31  * Reserved message opcodes used by libpdx. The reserved opcodes start at the
32  * max positive signed integer for the system and go down.
33  * In contrast, service opcodes start at zero and go up. This scheme leaves
34  * most of the positive integer space for services, a tiny fraction of the
35  * positive integer space for the framework, and the entire negative integer
36  * space for the kernel.
37  */
38 #define PDX_OPCODE(name, n) name = ((-1U >> 1) - (n))  // 0x7fff..ffff - n
39 
40 enum {
41   // System message sent when a new client channel is open.
42   CHANNEL_OPEN = -1,
43   // System message sent when a channel is closed.
44   CHANNEL_CLOSE = -2,
45   // Request the service to reload system properties.
46   PDX_OPCODE(REPORT_SYSPROP_CHANGE, 0),
47   // Request the service to dump state and return it in a text buffer.
48   PDX_OPCODE(DUMP_STATE, 1),
49 };
50 
51 }  // namespace opcodes
52 
53 /*
54  * Base class of service-side per-channel context classes.
55  */
56 class Channel : public std::enable_shared_from_this<Channel> {
57  public:
Channel()58   Channel() {}
~Channel()59   virtual ~Channel() {}
60 
61   /*
62    * Utility to get a shared_ptr reference from the channel context pointer.
63    */
64   static std::shared_ptr<Channel> GetFromMessageInfo(const MessageInfo& info);
65 };
66 
67 /*
68  * Message class represents an RPC message, and implicitly the blocked sender
69  * waiting for a response. Every message should get a reply, at some point
70  * (unless the endpoint is closed), to prevent clients from blocking
71  * indefinitely. In order to enforce this and prevent leaking message ids,
72  * Message automatically replies with an error to the client on destruction,
73  * unless one of two things happens:
74  *
75  *     1. The service calls one of the reply methods before the Message is
76  *        destroyed.
77  *     2. The responsibility for the message is moved to another instance of
78  *        Message, using either move construction or move assignment.
79  *
80  * The second case is useful for services that need to delay responding to a
81  * sender until a later time. In this situation the service can move the
82  * Message to another instance in a suitable data structure for later use. The
83  * moved-to Message then takes on the same behavior and responsibilities
84  * described above.
85  */
86 class Message : public OutputResourceMapper, public InputResourceMapper {
87  public:
88   Message();
89   Message(const MessageInfo& info);
90   ~Message();
91 
92   /*
93    * Message objects support move construction and assignment.
94    */
95   Message(Message&& other);
96   Message& operator=(Message&& other);
97 
98   /*
99    * Read/write payload, in either single buffer or iovec form.
100    */
101   Status<size_t> ReadVector(const iovec* vector, size_t vector_length);
102   Status<size_t> Read(void* buffer, size_t length);
103   Status<size_t> WriteVector(const iovec* vector, size_t vector_length);
104   Status<size_t> Write(const void* buffer, size_t length);
105 
106   template <size_t N>
ReadVector(const iovec (& vector)[N])107   inline Status<size_t> ReadVector(const iovec (&vector)[N]) {
108     return ReadVector(vector, N);
109   }
110 
111   template <size_t N>
WriteVector(const iovec (& vector)[N])112   inline Status<size_t> WriteVector(const iovec (&vector)[N]) {
113     return WriteVector(vector, N);
114   }
115 
116   // Helper functions to read/write all requested bytes, and return EIO if not
117   // all were read/written.
118   Status<void> ReadVectorAll(const iovec* vector, size_t vector_length);
119   Status<void> WriteVectorAll(const iovec* vector, size_t vector_length);
120 
ReadAll(void * buffer,size_t length)121   inline Status<void> ReadAll(void* buffer, size_t length) {
122     Status<size_t> status = Read(buffer, length);
123     if (status && status.get() < length)
124       status.SetError(EIO);
125     Status<void> ret;
126     ret.PropagateError(status);
127     return ret;
128   }
WriteAll(const void * buffer,size_t length)129   inline Status<void> WriteAll(const void* buffer, size_t length) {
130     Status<size_t> status = Write(buffer, length);
131     if (status && status.get() < length)
132       status.SetError(EIO);
133     Status<void> ret;
134     ret.PropagateError(status);
135     return ret;
136   }
137 
138   template <size_t N>
ReadVectorAll(const iovec (& vector)[N])139   inline Status<void> ReadVectorAll(const iovec (&vector)[N]) {
140     return ReadVectorAll(vector, N);
141   }
142 
143   template <size_t N>
WriteVectorAll(const iovec (& vector)[N])144   inline Status<void> WriteVectorAll(const iovec (&vector)[N]) {
145     return WriteVectorAll(vector, N);
146   }
147 
148   // OutputResourceMapper
149   Status<FileReference> PushFileHandle(const LocalHandle& handle) override;
150   Status<FileReference> PushFileHandle(const BorrowedHandle& handle) override;
151   Status<FileReference> PushFileHandle(const RemoteHandle& handle) override;
152   Status<ChannelReference> PushChannelHandle(
153       const LocalChannelHandle& handle) override;
154   Status<ChannelReference> PushChannelHandle(
155       const BorrowedChannelHandle& handle) override;
156   Status<ChannelReference> PushChannelHandle(
157       const RemoteChannelHandle& handle) override;
158 
159   // InputResourceMapper
160   bool GetFileHandle(FileReference ref, LocalHandle* handle) override;
161   bool GetChannelHandle(ChannelReference ref,
162                         LocalChannelHandle* handle) override;
163 
164   /*
165    * Various ways to reply to a message.
166    */
167   Status<void> Reply(int return_code);
168   Status<void> ReplyError(unsigned int error);
169   Status<void> ReplyFileDescriptor(unsigned int fd);
170   Status<void> Reply(const LocalHandle& handle);
171   Status<void> Reply(const BorrowedHandle& handle);
172   Status<void> Reply(const RemoteHandle& handle);
173   Status<void> Reply(const LocalChannelHandle& handle);
174   Status<void> Reply(const BorrowedChannelHandle& handle);
175   Status<void> Reply(const RemoteChannelHandle& handle);
176 
177   template <typename T>
Reply(const Status<T> & status)178   inline Status<void> Reply(const Status<T>& status) {
179     return status ? Reply(status.get()) : ReplyError(status.error());
180   }
181 
Reply(const Status<void> & status)182   inline Status<void> Reply(const Status<void>& status) {
183     return status ? Reply(0) : ReplyError(status.error());
184   }
185 
186   /*
187    * Update the channel event bits with the given clear and set masks.
188    */
189   Status<void> ModifyChannelEvents(int clear_mask, int set_mask);
190 
191   /*
192    * Create a new channel and push it as a file descriptor to the client. See
193    * Service::PushChannel() for a detail description of this method's operation.
194    */
195   Status<RemoteChannelHandle> PushChannel(
196       int flags, const std::shared_ptr<Channel>& channel, int* channel_id);
197 
198   /*
199    * Create a new channel and push it as a file descriptor to the client. See
200    * Service::PushChannel() for a detail description of this method's operation.
201    */
202   Status<RemoteChannelHandle> PushChannel(
203       Service* service, int flags, const std::shared_ptr<Channel>& channel,
204       int* channel_id);
205 
206   /*
207    * Check whether the |ref| is a reference to channel to this service.
208    * If the channel reference in question is valid, the Channel object is
209    * returned in |channel| when non-nullptr.
210    *
211    * Return values:
212    *  channel_id - id of the channel if the |ref| is a valid reference to
213    *               this service's channel.
214    * Errors:
215    *  EOPNOTSUPP - the file descriptor is not a channel or is a channel to
216    *  another service.
217    *  EBADF - the file descriptor is invalid.
218    *  FAULT - |channel_id| or |channel| are non-nullptr and point to invalid
219    *  memory addresses.
220    *  EINVAL - the value of |ref| is invalid or the message id for this
221    *           message is no longer valid.
222    */
223   Status<int> CheckChannel(ChannelReference ref,
224                            std::shared_ptr<Channel>* channel) const;
225 
226   /*
227    * Overload of CheckChannel() that checks whether the channel reference is for
228    * a channel to the service |service|.
229    */
230   Status<int> CheckChannel(const Service* service, ChannelReference ref,
231                            std::shared_ptr<Channel>* channel) const;
232 
233   /*
234    * Overload of CheckChannel() that automatically converts to shared pointers
235    * to types derived from Channel.
236    */
237   template <class C>
CheckChannel(ChannelReference ref,std::shared_ptr<C> * channel)238   Status<int> CheckChannel(ChannelReference ref,
239                            std::shared_ptr<C>* channel) const {
240     std::shared_ptr<Channel> base_pointer;
241     const Status<int> ret =
242         CheckChannel(ref, channel ? &base_pointer : nullptr);
243     if (channel)
244       *channel = std::static_pointer_cast<C>(base_pointer);
245     return ret;
246   }
247 
248   template <class C>
CheckChannel(const Service * service,ChannelReference ref,std::shared_ptr<C> * channel)249   Status<int> CheckChannel(const Service* service, ChannelReference ref,
250                            std::shared_ptr<C>* channel) const {
251     std::shared_ptr<Channel> base_pointer;
252     const Status<int> ret =
253         CheckChannel(service, ref, channel ? &base_pointer : nullptr);
254     if (channel)
255       *channel = std::static_pointer_cast<C>(base_pointer);
256     return ret;
257   }
258 
259   /*
260    * MessageInfo accessors.
261    */
262   pid_t GetProcessId() const;
263   pid_t GetThreadId() const;
264   uid_t GetEffectiveUserId() const;
265   gid_t GetEffectiveGroupId() const;
266   int GetChannelId() const;
267   int GetMessageId() const;
268   int GetOp() const;
269   int GetFlags() const;
270   size_t GetSendLength() const;
271   size_t GetReceiveLength() const;
272   size_t GetFileDescriptorCount() const;
273 
274   /*
275    * Impulses are asynchronous and cannot be replied to. All impulses have this
276    * invalid message id.
277    */
278   enum { IMPULSE_MESSAGE_ID = -1 };
279 
280   /*
281    * Returns true if this Message describes an asynchronous "impulse" message.
282    */
IsImpulse()283   bool IsImpulse() const { return GetMessageId() == IMPULSE_MESSAGE_ID; }
284 
285   /*
286    * Returns a pointer to the impulse payload. Impulses are a maximum of 32
287    * bytes in size and the start of the impulse payload is guaranteed to be
288    * 8-byte aligned. Use GetSendLength() to determine the payload size.
289    */
290   const std::uint8_t* ImpulseBegin() const;
291 
292   /*
293    * Returns one byte past the end of the impulse payload, as conventional for
294    * STL iterators.
295    */
296   const std::uint8_t* ImpulseEnd() const;
297 
298   /*
299    * Get/set the Channel object for the channel associated
300    * with this message. It is up to the caller to synchronize
301    * these in multi-threaded services.
302    */
303   std::shared_ptr<Channel> GetChannel() const;
304   Status<void> SetChannel(const std::shared_ptr<Channel>& channnel);
305 
306   /*
307    * Get the Channel object for the channel associated with this message,
308    * automatically converted to the desired subclass of Channel.
309    */
310   template <class C>
GetChannel()311   std::shared_ptr<C> GetChannel() const {
312     return std::static_pointer_cast<C>(GetChannel());
313   }
314 
315   /*
316    * Gets the service this message was received on. Returns nullptr if the
317    * service was destroyed.
318    */
319   std::shared_ptr<Service> GetService() const;
320 
321   /*
322    * Raw access to the MessageInfo for this message.
323    */
324   const MessageInfo& GetInfo() const;
325 
replied()326   bool replied() const { return replied_; }
IsChannelExpired()327   bool IsChannelExpired() const { return channel_.expired(); }
IsServiceExpired()328   bool IsServiceExpired() const { return service_.expired(); }
329 
330   /*
331    * Returns true if the message is non-empty; that is the message can be
332    * replied to using this instance.
333    */
334   explicit operator bool() const { return !replied_; }
335 
GetState()336   const void* GetState() const { return state_; }
GetState()337   void* GetState() { return state_; }
338 
339  private:
340   friend class Service;
341 
342   Message(const Message&) = delete;
343   void operator=(const Message&) = delete;
344   void Destroy();
345 
346   std::weak_ptr<Service> service_;
347   std::weak_ptr<Channel> channel_;
348   MessageInfo info_;
349   void* state_{nullptr};
350   bool replied_;
351 };
352 
353 // Base class for RPC services.
354 class Service : public std::enable_shared_from_this<Service> {
355  public:
356   Service(const std::string& name, std::unique_ptr<Endpoint> endpoint);
357   virtual ~Service();
358 
359   /*
360    * Utility to get a shared_ptr reference from the service context pointer.
361    */
362   static std::shared_ptr<Service> GetFromMessageInfo(const MessageInfo& info);
363 
364   /*
365    * Returns whether initialization was successful. Subclasses that override
366    * this must call this base method and AND the results with their own. This
367    * method is not intended to do any initialization work itself, only to
368    * signal success or failure.
369    */
370   virtual bool IsInitialized() const;
371 
372   /*
373    * Called by defaultHandleMessage in response to a CHANNEL_OPEN message.
374    * This gives subclasses of Service a convenient hook to create per-channel
375    * context in the form of a Channel subclass.
376    *
377    * The Channel instance returned by this is used to set the channel context
378    * pointer for the channel that was just opened.
379    */
380   virtual std::shared_ptr<Channel> OnChannelOpen(Message& message);
381 
382   /*
383    * Called by defaultHandleMessage in response to a CHANNEL_CLOSE message.
384    * This give subclasses of Service a convenient hook to clean up per-channel
385    * context.
386    */
387   virtual void OnChannelClose(Message& message,
388                               const std::shared_ptr<Channel>& channel);
389 
390   /*
391    * Set the channel context for the given channel. This keeps a reference to
392    * the Channel object until the channel is closed or another call replaces
393    * the current value.
394    */
395   Status<void> SetChannel(int channel_id,
396                           const std::shared_ptr<Channel>& channel);
397 
398   /*
399    * Get the channel context for the given channel id. This method should be
400    * used sparingly because of the performance characteristics of the underlying
401    * map; it is intended for limited, non-critical path access from outside of
402    * message dispatch. In most cases lookup by id should be unnecessary in a
403    * properly designed service; Message::GetChannel() should be used instead
404    * whenever an operation is in the context of a message.
405    *
406    * Again, if you lookup a channel context object for a service by id in a
407    * message handling path for the same service, you're probably doing something
408    * wrong.
409    */
410   std::shared_ptr<Channel> GetChannel(int channel_id) const;
411 
412   /*
413    * Get a snapshot of the active channels for this service. This is the
414    * preferred way to access the set of channels because it avoids potential
415    * deadlocks and race conditions that may occur when operating on the channel
416    * map directly. However, it is more expensive than direct iteration because
417    * of dynamic memory allocation and shared pointer reference costs.
418    *
419    * Automatically converts returned items to shared pointers of the type
420    * std::shared_ptr<C>, where C is the subclass of Channel used by the service.
421    */
422   template <class C>
GetChannels()423   std::vector<std::shared_ptr<C>> GetChannels() const {
424     std::lock_guard<std::mutex> autolock(channels_mutex_);
425     std::vector<std::shared_ptr<C>> items;
426     items.reserve(channels_.size());
427 
428     for (const auto& pair : channels_) {
429       items.push_back(std::static_pointer_cast<C>(pair.second));
430     }
431 
432     return items;
433   }
434 
435   /*
436    * Close a channel, signaling the client file object and freeing the channel
437    * id. Once closed, the client side of the channel always returns the error
438    * ESHUTDOWN and signals the poll/epoll events POLLHUP and POLLFREE.
439    *
440    * The internal reference to the Channel instance associated with the channel
441    * is removed, which may result in the Channel object being freed.
442    *
443    * OnChannelClosed is not called in response to this method call.
444    */
445   Status<void> CloseChannel(int channel_id);
446 
447   /*
448    * Update the event bits for the given channel (given by id), using the
449    * given clear and set masks.
450    *
451    * This is useful for asynchronously signaling events that clients may be
452    * waiting for using select/poll/epoll.
453    */
454   Status<void> ModifyChannelEvents(int channel_id, int clear_mask,
455                                    int set_mask);
456 
457   /*
458    * Create a new channel and push it as a file descriptor to the process
459    * sending the |message|. |flags| may be set to O_NONBLOCK and/or
460    * O_CLOEXEC to control the initial behavior of the new file descriptor (the
461    * sending process may change these later using fcntl()). The internal Channel
462    * instance associated with this channel is set to |channel|, which may be
463    * nullptr. The new channel id allocated for this channel is returned in
464    * |channel_id|, which may also be nullptr if not needed.
465    *
466    * On success, returns the remote channel handle for the new channel in the
467    * sending process' handle space. This MUST be returned to the sender via
468    * Message::Reply(), Message::Write(), or Message::WriteVector().
469    *
470    * On error, returns an errno code describing the cause of the error.
471    *
472    * Service::OnChannelCreate() is not called in response to the creation of the
473    * new channel.
474    */
475   Status<RemoteChannelHandle> PushChannel(
476       Message* message, int flags, const std::shared_ptr<Channel>& channel,
477       int* channel_id);
478 
479   /*
480    * Check whether the |ref| is a reference to a channel to this service.
481    * If the channel reference in question is valid, the Channel object is
482    * returned in |channel| when non-nullptr.
483    *
484    * Return values:
485    *  channel_id - id of the channel if the channel reference.
486    * Errors:
487    *  EOPNOTSUPP - the file descriptor is not a channel or is a channel to
488    *  another service.
489    *  EBADF - the file descriptor is invalid.
490    *  FAULT - |channel_id| or |channel| are non-nullptr and point to invalid
491    *  memory addresses.
492    *  EINVAL - the value of |ref| is invalid or the message id for this
493    *  message is no longer valid.
494    */
495   Status<int> CheckChannel(const Message* message, ChannelReference ref,
496                            std::shared_ptr<Channel>* channel) const;
497 
498   /*
499    * Overload of CheckChannel() that automatically converts to shared pointers
500    * of types derived from Channel.
501    */
502   template <class C>
CheckChannel(const Message * message,ChannelReference ref,std::shared_ptr<C> * channel)503   Status<int> CheckChannel(const Message* message, ChannelReference ref,
504                            std::shared_ptr<C>* channel) const {
505     std::shared_ptr<Channel> base_pointer;
506     const Status<int> ret =
507         CheckChannel(message, ref, channel ? &base_pointer : nullptr);
508     if (channel)
509       *channel = std::static_pointer_cast<C>(base_pointer);
510     return ret;
511   }
512 
513   /*
514    * Handle a message. Subclasses override this to receive messages and decide
515    * how to dispatch them.
516    *
517    * The default implementation simply calls defaultHandleMessage().
518    * Subclasses should call the same for any unrecognized message opcodes.
519    */
520   virtual Status<void> HandleMessage(Message& message);
521 
522   /*
523    * Handle an asynchronous message. Subclasses override this to receive
524    * asynchronous "impulse" messages. Impulses have a limited-size payload that
525    * is transferred upfront with the message description.
526    */
527   virtual void HandleImpulse(Message& impulse);
528 
529   /*
530    * The default message handler. It is important that all messages
531    * (eventually) get a reply. This method should be called by subclasses for
532    * any unrecognized opcodes or otherwise unhandled messages to prevent
533    * erroneous requests from blocking indefinitely.
534    *
535    * Provides default handling of CHANNEL_OPEN and CHANNEL_CLOSE, calling
536    * OnChannelOpen() and OnChannelClose(), respectively.
537    *
538    * For all other message opcodes, this method replies with ENOTSUP.
539    */
540   Status<void> DefaultHandleMessage(Message& message);
541 
542   /*
543    * Called when system properties have changed. Subclasses should implement
544    * this method if they need to handle when system properties change.
545    */
546   virtual void OnSysPropChange();
547 
548   /*
549    * Get the endpoint for the service.
550    */
endpoint()551   Endpoint* endpoint() const { return endpoint_.get(); }
552 
553   /*
554    * Cancels the endpoint, unblocking any receiver threads waiting in
555    * ReceiveAndDispatch().
556    */
557   Status<void> Cancel();
558 
559   /*
560    * Iterator type for Channel map iterators.
561    */
562   using ChannelIterator =
563       std::unordered_map<int, std::shared_ptr<Channel>>::iterator;
564 
565   /*
566    * Iterates over the Channel map and performs the action given by |action| on
567    * each channel map item (const ChannelIterator::value_type).
568    * |channels_mutex_| is not held; it is the responsibility of the caller to
569    * ensure serialization between threads that modify or iterate over the
570    * Channel map.
571    */
572   template <class A>
ForEachChannelUnlocked(A action)573   void ForEachChannelUnlocked(A action) const {
574     std::for_each(channels_.begin(), channels_.end(), action);
575   }
576 
577   /*
578    * Iterates over the Channel map and performs the action given by |action| on
579    * each channel map item (const ChannelIterator::value_type).
580    * |channels_mutex_| is held to serialize access to the map; care must be
581    * taken to avoid recursively acquiring the mutex, for example, by calling
582    * Service::{GetChannel,SetChannel,CloseChannel,PushChannel}() or
583    * Message::SetChannel() in the action.
584    */
585   template <class A>
ForEachChannel(A action)586   void ForEachChannel(A action) const {
587     std::lock_guard<std::mutex> autolock(channels_mutex_);
588     ForEachChannelUnlocked(action);
589   }
590 
591   /*
592    * Subclasses of Service may override this method to provide a text string
593    * describing the state of the service. This method is called by
594    * HandleSystemMessage in response to the standard
595    * DUMP_STATE message. The string returned to the dump state client is
596    * truncated to |max_length| and reflects the maximum size the client can
597    * handle.
598    */
599   virtual std::string DumpState(size_t max_length);
600 
601   /*
602    * Receives a message on this Service instance's endpoint and dispatches it.
603    * If the endpoint is in blocking mode this call blocks until a message is
604    * received, a signal is delivered to this thread, or the service is canceled.
605    * If the endpoint is in non-blocking mode and a message is not pending this
606    * call returns immediately with ETIMEDOUT.
607    */
608   Status<void> ReceiveAndDispatch();
609 
610  private:
611   friend class Message;
612 
613   Status<void> HandleSystemMessage(Message& message);
614 
615   Service(const Service&);
616   void operator=(const Service&) = delete;
617 
618   const std::string name_;
619   std::unique_ptr<Endpoint> endpoint_;
620 
621   /*
622    * Maintains references to active channels.
623    */
624   mutable std::mutex channels_mutex_;
625   std::unordered_map<int, std::shared_ptr<Channel>> channels_;
626 };
627 
628 /*
629  * Utility base class for services. This template handles allocation and
630  * initialization checks, reducing boiler plate code.
631  */
632 template <typename TYPE>
633 class ServiceBase : public Service {
634  public:
635   /*
636    * Static service allocation method that check for initialization errors.
637    * If errors are encountered these automatically clean up and return
638    * nullptr.
639    */
640   template <typename... Args>
Create(Args &&...args)641   static inline std::shared_ptr<TYPE> Create(Args&&... args) {
642     std::shared_ptr<TYPE> service(new TYPE(std::forward<Args>(args)...));
643     if (service->IsInitialized())
644       return service;
645     else
646       return nullptr;
647   }
648 
649  protected:
650   /*
651    * Shorthand for subclasses to refer to this base, particularly
652    * to call the base class constructor.
653    */
654   typedef ServiceBase<TYPE> BASE;
655 
ServiceBase(const std::string & name,std::unique_ptr<Endpoint> endpoint)656   ServiceBase(const std::string& name, std::unique_ptr<Endpoint> endpoint)
657       : Service(name, std::move(endpoint)) {}
658 };
659 
660 #ifndef STRINGIFY
661 #define STRINGIFY2(s) #s
662 #define STRINGIFY(s) STRINGIFY2(s)
663 #endif
664 
665 #define PDX_ERROR_PREFIX "[" __FILE__ ":" STRINGIFY(__LINE__) "]"
666 
667 /*
668  * Macros for replying to messages. Error handling can be tedious;
669  * these macros make things a little cleaner.
670  */
671 #define CHECK_ERROR(cond, error, fmt, ...) \
672   do {                                     \
673     if ((cond)) {                          \
674       ALOGE(fmt, ##__VA_ARGS__);           \
675       goto error;                          \
676     }                                      \
677   } while (0)
678 
679 #define REPLY_ERROR(message, error, error_label)                              \
680   do {                                                                        \
681     auto __status = message.ReplyError(error);                                \
682     CHECK_ERROR(!__status, error_label,                                       \
683                 PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \
684                 __status.GetErrorMessage().c_str());                          \
685     goto error_label;                                                         \
686   } while (0)
687 
688 #define REPLY_ERROR_RETURN(message, error, ...)                          \
689   do {                                                                   \
690     auto __status = message.ReplyError(error);                           \
691     ALOGE_IF(!__status,                                                  \
692              PDX_ERROR_PREFIX " Failed to reply to message because: %s", \
693              __status.GetErrorMessage().c_str());                        \
694     return __VA_ARGS__;                                                  \
695   } while (0)
696 
697 #define REPLY_MESSAGE(message, message_return_code, error_label)              \
698   do {                                                                        \
699     auto __status = message.Reply(message_return_code);                       \
700     CHECK_ERROR(!__status, error_label,                                       \
701                 PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \
702                 __status.GetErrorMessage().c_str());                          \
703     goto error_label;                                                         \
704   } while (0)
705 
706 #define REPLY_SUCCESS(message, message_return_code, error_label) \
707   REPLY_MESSAGE(message, message_return_code, error_label)
708 
709 #define REPLY_MESSAGE_RETURN(message, message_return_code, ...)          \
710   do {                                                                   \
711     auto __status = message.Reply(message_return_code);                  \
712     ALOGE_IF(!__status,                                                  \
713              PDX_ERROR_PREFIX " Failed to reply to message because: %s", \
714              __status.GetErrorMessage().c_str());                        \
715     return __VA_ARGS__;                                                  \
716   } while (0)
717 
718 #define REPLY_SUCCESS_RETURN(message, message_return_code, ...) \
719   REPLY_MESSAGE_RETURN(message, message_return_code, __VA_ARGS__)
720 
721 #define REPLY_FD(message, push_fd, error_label)                               \
722   do {                                                                        \
723     auto __status = message.ReplyFileDescriptor(push_fd);                     \
724     CHECK_ERROR(!__status, error_label,                                       \
725                 PDX_ERROR_PREFIX " Failed to reply to message because: %s\n", \
726                 __status.GetErrorMessage().c_str());                          \
727     goto error_label;                                                         \
728   } while (0)
729 
730 #define REPLY_FD_RETURN(message, push_fd, ...)                           \
731   do {                                                                   \
732     auto __status = message.ReplyFileDescriptor(push_fd);                \
733     ALOGE_IF(__status < 0,                                               \
734              PDX_ERROR_PREFIX " Failed to reply to message because: %s", \
735              __status.GetErrorMessage().c_str());                        \
736     return __VA_ARGS__;                                                  \
737   } while (0)
738 
739 }  // namespace pdx
740 }  // namespace android
741 
742 #endif  // ANDROID_PDX_SERVICE_H_
743