Good practice for multi-publisher, multi-subscriber data exchange on Android - android

I am working on sharing road traffic information between Android applications, and wondering what is a good transport mechanism.
There are two classes of applications: Publishers post traffic messages they have obtained from various sources (say, an Internet service or a TMC receiver device) and converted to a standard format. Subscribers listen for messages and work with them (e.g. displaying them in a list or guiding drivers around congestions). The system is intended to be decentral: there will be multiple publishers, multiple subscribers and users can mix and match them as they like.
Messages are identified by a unique ID, which remains stable over their entire life cycle. They have an expiration time, after which they are considered invalid. Until then, they can be updated at any time. An update can also cancel the message (replacing it with a tombstone until it expires), or extend its expiration time.
Subscribers get new messages as they arrive. (Filtering may happen in a later phase.) They also need a way to retrieve all currently cached messages from all publishers.
A message is around 1 kByte in size. A publisher can easily hold several hundred active messages at any given time.
In terms of security, the messages are generally public information. The only sensitive information is geodata, as it may allow for conclusions on the location of the device or where its user intends to travel. The precision of such data is low, anywhere from city to country level. Therefore I don’t see a need to hide this information from any app, as long as it has location permission.
Now I am wondering what a good transport mechanism would be:
Option 1: Broadcast intents
Initially I have been working with broadcast intents: whenever a publisher has any new messages, it sends an implicit broadcast with the messages in the extras. Subscribers can register a broadcast receiver at run time to receive messages. They also have the option to send a poll broadcast (an explicit broadcast, with the corresponding broadcast receiver declared in the publisher’s Manifest). Publishers will then respond with a feed of all currently cached messages. To address security concerns, any app sending a broadcast with geodata requires that the receiver hold one of the location permissions.
There is an issue with large feeds, as the Android request broker supports a maximum of 1 MByte for all concurrent transactions (so the maximum amount of data in a feed can be even less if things are busy). I am currently working around that by breaking down feeds into chunks of 100 messages or less.
An advantage of this system is that all central infrastructure is provided by the OS. Having one publisher and one subscriber app installed is sufficient.
Option 2: Content Providers
Some people have pointed out that broadcast intents are not the best way to go, and have suggested I implement a content provider, a territory into which I have not ventured so far. Looking at the documentation, it is not clear if there is a way to have multiple backends (each backend being a separate app) implement functionally identical content providers and advertise them as such. Since content providers support both read and write operations, I could set up one central component as the content provider, and have both publishers and subscribers connect to it. However, that would require providing a central component in order to work, which I would rather avoid.
Questions:
Is there a way to implement the above multi-publisher, multi-subscriber model with content providers, and without having to supply a central component not already provided by the OS?
Specifically, can a single content provider have multiple backends? Alternatively, can multiple, functionally identical content providers advertise themselves as a group?
How would I implement the above using content providers?
What are advantages and drawbacks of broadcast intents or content providers that I may have missed?

Is there a way to implement the above multi-publisher, multi-subscriber model with content providers
Keep the broadcasts. Replace the payload.
Publishers would implement a ContentProvider that serve up the current roster of messages. You can think of a ContentProvider as being a quirky sort of REST-style Web service, where Uri values get mapped to responses by the provider.
Publishers would then send broadcasts as they are today, but perhaps with only two extras:
One that identifies the protocol version that the broadcast is using, since you have lots of independently-updated parties. Rceivers need to know how to interpret the broadcast, as you might change the rules over time.
One that contains a Uri pointing to the publisher's ContentProvider.
If there are other extras that you are using today that you know will remain small, and you want to still put those in the broadcast, that's cool. Just keep the indeterminate-sized ones out of the broadcast.
Receivers would then:
Look at the protocol version extra and branch to the code to handle that version (today, just one branch, but, hey, future-proofing)
Use that Uri and a ContentResolver to get the messages (and other stuff if needed) from the publisher
You might consider developing this communications infrastructure as an SDK. Even if you are the only one developing apps, you'll want to avoid duplicating all this logic across the apps. And, if third parties will develop apps, you're better off giving them an SDK to work from, rather than forcing them "roll their own".

Related

What is a reliable way of sending messages between process in Android?

I'm an Android newbie. I'm trying to send and receive messages between process. One thing which I'm aware of is communicating via binder calls by implementing a Service. The other message transferring mechanism which I've seen so far is
Broadcast (Not reliable though) - which can be missed
Event bus (Not sure IPC is possible with greenrobot's event bus - this SO link says it's not possible and suggested for alternatives
Registering a ContentObserver so that I can update my content at one process and the other process can get notified of the content change (Not sure this is reliable)
All I mean by reliable is that it can be missed at rare cases. Is there any alternative reliable and ordered (delivered in the same order in which it's published) - message exchanging mechanism between processes in Android?
EDIT: Though there are many ways discussed in this SO Link I would like to maintain the message order and guaranteed delivery of message.

Content-Resolver Explanation

anyone knows why the Android developers team have implemented the Content-Resolver as a middleman to get data from a Content-Provider. Why not asking data directly from the Content-Provider ?
It means that the Content-Resolver has a special job, what is it ?
Why not asking data directly from the Content-Provider ?
A content: Uri may refer to a ContentProvider in another app. You cannot work with that ContentProvider directly; inter-process communication (IPC) is required. Hence, the API was designed around that IPC model.
ContentResolvers are designed to create an interface for applications to securely access and/or modify data in other applications which run in separate processes. It creates a common contract for content consumer registrations, requests, updates, binding, etc. to be passed between a particular ContentProvider and the content consumer that runs in another process.
Creating a proper and durable interface for transferring data across processes in Android is complex. If you had to create your own IPC client then it would be time consuming and you would likely overlook important aspects of the implementation. A "direct" connection to the ContentProvider is what a ContentResolver provides, but with a lot of the complexity already addressed. It is a convenience to already have that created and well-defined on both sides.
This is a little like a postal delivery system. If you use the postal service, you put an address on a piece of mail and the postal service (ContentResolver) finds the appropriate place to deliver the message (ContentProvider), and then returns any messages to you in response to your message. Your postal service will also handle new address registrations, tell you if the address is invalid, if the package is too big, if the recipient at the destination address is not accepting messages right now, waits if the message queue is full, handles situations where the vehicle carrying the message breaks down, etc. And in the case of ContentResolvers there are a few other things.
You could handle all of that yourself but when you think about real-life message delivery, it's not simple and much easier to use something built by someone else. Likewise for interprocess communication (IPC) in Android. It's not a perfect analogy but hopefully that helps clarify the need for a ContentResolver.

Intent vs Content Provider in android

I am new in android app development and while studying about the basic android components I got confused between intents and content provider as both are being used to send data from one application/component to another application/component . In case of intents we can send data using bundle or extras so why do we use content providers. Can someone please explain me this with a example . Also can we access database in android only using content provider and is this the sole reason why we use content providers ?
both are being used to send data from one application/component to another application/component
Not really.
There are four components in Android:
Activity
Service
BroadcastReceiver
ContentProvider
An Intent is none of those. An Intent is involved when we start an activity, start or bind to a service, or send a broadcast. However, comparing an Intent to a ContentProvider is akin to comparing a shovel with a boot, arguing that both can be used to carry dirt. While true, usually a boot is involved in carrying dirt, but the actual means of carrying dirt is handled by something else, such as a wheelbarrow.
In case of intents we can send data using bundle or extras so why do we use content providers.
We often use different tools for different circumstances. For example, you will find it rather difficult to carry water in a fishing net.
Each of the four components has a different role, particularly in relationship to inter-process communication (IPC):
An Activity drives the bulk of our user interface, including starting up activities from other apps (or having one of our activities be started by other apps)
A Service exists for longer-running operations that are logically decoupled from the user interface, including working with services that are implemented by other apps (or having other apps work with services that you publish)
A BroadcastReceiver is a publish/subscribe messaging system, to allow you to send messages to arbitrary subscribers, or to subscribe to messages from arbitrary senders, across process boundaries
A ContentProvider is for bulk data transfer, whether in the form of a database-style structure (rows and columns) or in the form of a stream, particularly for working with other apps
Also can we access database in android only using content provider
No. After all, if that were true, it would be impossible to access a database. A ContentProvider does not appear by magic. It has to be written by a programmer. If a ContentProvider could only access a database by means of a ContentProvider, we would have a problem.
is this the sole reason why we use content providers ?
No. In addition to offering a database-style API, a ContentProvider can also publish a stream. This is important for getting arbitrary data between apps, such as an email client making a PDF attachment available to a PDF viewer.
Intents are a messaging architecture for sending /receiving transactional commands and data. Content providers are an abstract interface to stored data for create,update, delete and sync operations.

Requesting other application data

What would be good approach to establish communication between different APKs? One app can send request to other apps and wait for response.
I can think of:
1. using BroadCast receivers: send "request" broadcast and receive returned broadcasts (results). This seems nice clean solution, no security problems, but how to get all results back as "one" - usually I will want to send out broadcast to collect app identifications, and get result like array.
2. use sharedUserId between all these apps and gather or execute whatever I need directly on the apps. But here are have couple of more loose ends:
- how do I get list of apps (through list of installed packages?)
- is with sharedUserId and same signature possible to access other app internals? like register/unregister component, etc.?
Thanks!
EDIT:
Have been reading more about ordered broadcasts and so far this seems good way to go. Using order broadcast each of other apps will fill in its own data part and result will be returned back to supplied "final" receiver.
I am using ordered broadcasts. When broadcast is send out, each receiver adds its information and last receiver calls resultReceiver.

ContentProvider or Service?

I am writing an application that shows "Japanese Traditional Time" (JTT for short). There are several components (notification, widgets, application itself, alarms) which all use the same data - current JTT.
My current version uses a single service that does all the calculation and uses a Handler to notify everyone about "ticking", mimicking ACTION_TIME_TICK.
However with alarms I need to also have a way to translate "usual time" to JTT and vice versa. The calculations are quite CPU-heavy (it's all based on sunrises and sunsets) and thus I prefer having it all done in a single place and then cached (calculating stuff knowing sunrise and sunset times is not as heavy).
So I have several ways to do that now:
Keep it all in Service
And use binding to request the data I need. It's actually already done in one case and seems a bit cumbersome since I have to handle asynchronous responses
Move to content provider
And use content observers instead of broadcasting
Or send broadcasts from provider
Combine both ways
Use content provider to calculate the data for service which in turn will broadcast it when needed
Which would be better? Maybe something else?
Content providers are for structured data, so it doesn't really fit your use case. Not sure what you mean by 'asynchronous responses'? Calling a remote service is usually just like a local function call, it will block and return a value when done. If you have to notify multiple components a broadcast is the way to go. Explore using a LocalBroadcast if all components are in the same process (check Android support library source), or set a permission on it to make sure other apps cannot get it if you need to send a system-wide (regular) one.
I'm sticking with "just service" - I have discovered Sticky Broadcasts which actually cover the problem I had with common Broadcasts (having to request latest data from service after registering but before getting the first "tick") and that leaves me with much less cases where I need actual service connection.

Categories

Resources