Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for running service in a separate process #479

Merged
merged 12 commits into from
May 5, 2017

Conversation

davidgyoung
Copy link
Member

@davidgyoung davidgyoung commented Mar 11, 2017

This adds support for running the beacon scanning service in a separate process and working with application setups that have more than one process. This is needed in two cases:

  1. Where you are using another library that requires running in its own process (e.g. Google Cloud Messaging, Nokia HERE maps, etc.)
  2. Where you want the scanning service to run in its own process.

This addresses the problems described in #306

The change includes:

  • New IPC data exchange mechanism using Bundle and Serializable objects rather than the Parcelable method before. The new mechanism has the added benefit of being faster.
  • Adds tools to determine if the scanning process is running on the main process or a separate one.
  • New way of updating the scanning process with library configuration settings that does not rely on the BeaconManager or other classes being in the same process with the scanning service. (More work to do here, as synchronization of settings is very limited.)

In order to test this with an app you can force the BeaconService to run in a separate process by adding this entry to your application's manifest:

        <service android:enabled="true"
                 android:exported="false"
                 android:process=":BeaconService"
                 android:isolatedProcess="false"
                 android:label="beacon"
                 android:name="org.altbeacon.beacon.service.BeaconService"
                 tools:node="replace"
            />

If configuring beacon scanning using a custom Application class, this Application class will get started once for each process. You will only want to perform the setup activities once, typically in the main process that hosts the UI. You can do this using the beaconManager.isMainProcess() helper as shown:

    public void onCreate() {
        super.onCreate();

        // If you are running the beacon scanning service in a separate process, you should only
        // instantiate RegionBootstrap and BackgroundPowerSaver on a single process, as you only
        // want perform these functions once for the main process of the application.
          BeaconManager beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
        if (beaconManager.isMainProcess()) {
            regionBootstrap = new RegionBootstrap(this, mRegion);
            backgroundPowerSaver = new BackgroundPowerSaver(this);
            beaconManager.getBeaconParsers().clear();
            beaconManager.getBeaconParsers().add(new BeaconParser().
                    setBeaconLayout(MY_BEACON_LAYOUT));
            beaconManager.applySettings(); // Needed only if scanning process is in separate
        }
    }

@davidgyoung
Copy link
Member Author

@davidgyoung
Copy link
Member Author

The addMonitorNotifer and addRangeNotifer methods will need to be disabled for the BeaconManager instance that exists in the separate scanning process, as the callbacks will only function properly on the main process. Same should probably be true for constructing a BackgroundPowerSaver or RegionBootstrap. A RuntimeException is probably appropriate so it does not break the API.

@davidgyoung
Copy link
Member Author

Here is a description of how this PR affects library settings when the BeaconService is configured to run in its own process. This change does not affect settings when running in the same process.

Settings respected:

The following settings may be changed the same way regardless of whether the BeaconService
is running in a separate process.

beaconManager.getBeaconParsers().add(...) 
beaconManager.setBackgroundScanPeriod(...) 
beaconManager.setBackgroundBetweenScanPeriod(...)
beaconManager.setRegionStatePersistenceEnabled(...)
BeaconManager.setAndroidLScanningDisabled(...)
BeaconManager.setRegionExitPeriod(...)
BeaconManager.setUseTrackingCache(...)

Settings requiring modifications:

The following settings will only be applied if beaconManager.applySettings() is called
for cases where the BeaconService is running in a separate process. This call to
beaconManager.applySettings() is not necessary if the BeaconService is running in the
same process.

Beacon.setHardwareEqualityEnforced(...)

Settings ignored

The following settings are ignored when made from the main process and the BeaconScanner
is running on a separate process. Although they are ignored, the library continues to
function as normal with its default settings. If these methods are invoked with this
configuration in place, a warning generally will be logged:
"Unsupported configuration change made for BeaconScanner in separate process"

BeaconManager.setDistanceModelUpdateUrl(...)
BeaconManager.setRssiFilterImplClass(...)
BeaconManager.setBeaconSimulator(...)

@davidgyoung davidgyoung changed the title Add support for running service in a separate process (work in progress) Add support for running service in a separate process Apr 21, 2017
@paulbao
Copy link

paulbao commented Oct 10, 2017

@davidgyoung As you said The addMonitorNotifer and addRangeNotifer methods will need to be disabled for the BeaconManager instance that exists in the separate scanning process, how to get monitor/range notified if BeaconService is running in the separate process?

@davidgyoung
Copy link
Member Author

@paulbao, if you have a two process setup, you can freely access the range/monitor notifiers from your main app process that does not host the beacon scanning service. You simply cannot access and modify them from the process that does host the scanning service. This is because the library relies on a singleton manager to hold these notifiers (one singleton instance exists per process) and it is not kept in sync across processes.

@paulbao
Copy link

paulbao commented Oct 10, 2017

Thanks for quick reply @davidgyoung , I'm a little bit confused that range/monitor notifiers are interface, shouldn't I implemented them somewhere(Used to be BeaconManager.addRangeNotifer()) then I can got the callback.

@davidgyoung
Copy link
Member Author

davidgyoung commented Oct 10, 2017 via email

@cupakromer cupakromer deleted the separate-process-service-support branch November 29, 2017 00:01
cupakromer added a commit that referenced this pull request Dec 12, 2017
This fixes a minor issue where the running average is not set after
restoring a beacon from a parcel. Looking at the history it seems that
the running average was an internal detail until #479 where support was
added for running the service in a separate process.

Part of the reason this needs to be included is that on Android 8.0 the
running average _is_ restored and available for access. The reason the
behavior is different across Android versions is in the way a service
intent versus local notification handles the data `Bundle` (i.e. which
[`Callback`](https://github.com/AltBeacon/android-beacon-library/blob/2.12.3/src/main/java/org/altbeacon/beacon/service/Callback.java#L58-L86)
branch runs). Explicitly setting the `BeaconManager` to use scheduled
scan jobs, forcing the first conditional code path using local
notifications, allows the running average to be available on older
versions.
cupakromer added a commit that referenced this pull request Dec 12, 2017
This fixes a minor issue where the running average is not set after
restoring a beacon from a parcel. Looking at the history it seems that
the running average was an internal detail until #479 where support was
added for running the service in a separate process.

Part of the reason this needs to be included is that on Android 8.0 the
running average _is_ restored and available for access. The reason the
behavior is different across Android versions is in the way a service
intent versus local notification handles the data `Bundle` (i.e. which
[`Callback`](https://github.com/AltBeacon/android-beacon-library/blob/2.12.3/src/main/java/org/altbeacon/beacon/service/Callback.java#L58-L86)
branch runs). Explicitly setting the `BeaconManager` to use scheduled
scan jobs, forcing the first conditional code path using local
notifications, allows the running average to be available on older
versions.
@kanagalraj
Copy link

kanagalraj commented Jan 29, 2019

@davidgyoung
I am using the ALTBeacon to detect BLE proximity range, looks like there are multiple threads getting created by the library. This is impacting the thread scheduling time allocated for application's thread. I see that there is no way to run the scanning in separate process if we use the range and monitor notifier. Can you help us on what is best way to avoid the Beacon library threads impacting the application's thread scheduling time?

@davidgyoung
Copy link
Member Author

@kanagalraj, this is the first report I have heard of library threads (which are used to parse beacon packets when they arrive) impacting other functions. I suspect the issue you are experiencing may have a different root cause than you expect. Either way, please post a question on StackOverflow.com showing your setup code and any logs or other evidence showing the symptoms you are seeing. Glad to take a look there.

@kanagalraj
Copy link

@davidgyoung
I have created a question on stackOverflow.com showing setup code with pseudo code. https://stackoverflow.com/q/54443521/1985123

@bio007
Copy link

bio007 commented Mar 13, 2019

@davidgyoung I'm trying to use the library (v 2.16.1) in a separate process - I'm starting it from the service running separate process. There is no code regarding beacons running in main process.

Trying to setup ranging notifier I'm getting no reading nor exceptions / errors. When I remove android:process from the service declaration it starts to work. You mentioned there are singletons in the backround so there could be problems using it cross-process but I want everything done in one (services's) process.

Any help? :) Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants