Closed shankari closed 3 months ago
Here's the list of potential android API changes: https://developer.android.com/about/versions/14/summary
The ones that are potentially relevant to us are:
The SCHEDULE_EXACT_ALARM
permission: This is indeed from local notifications
$ grep -r SCHEDULE_EXACT_ALARM plugins/
plugins//cordova-plugin-local-notification-12/plugin.xml: <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
Fortunately, we use our own plugin, so we can change it however we want.
Here's where the alarms are scheduled, and they are in fact scheduled using setExact
and setAlarmClock
.
Let's change setExact
to set
, and setAlarmClock
(for the high priority case) to setAndAllowWhileIdle
consistent with https://developer.android.com/develop/background-work/services/alarms/schedule#inexact-after-specific-time. set
will not show the alarm in doze mode, setAndAllowWhenIdle
will
Like set, but this alarm will be allowed to execute even when the system is in low-power idle (a.k.a. doze) modes")
but with some limits
To reduce abuse, there are restrictions on how frequently these alarms will go off for a particular application. Under normal system operation, it will not dispatch these alarms more than about every minute (at which point every such pending alarm is dispatched); when in low-power idle modes this duration may be significantly longer, such as 15 minutes
that we easily meet since we only generate the alarm once a day.
Context-registered broadcasts are queued while apps are cached
So the only context-registered broadcasts are the two in plugins//cordova-plugin-em-datacollection/src/android/location/actions/GeofenceActions.java
and plugins//com.unarin.cordova.beacon/src/android/LocationManager.java
.
So unless the foreground service is killed, we will not have a cached process, so this won't apply to us.
The geofence is fine; we should just verify that, if the foreground service is killed and the bluetooth status changes in the interim, we re-check the status when the foreground service is recreated, and prompt the user to fix the permissions.
Foreground service types are required
✔️ If your app targets Android 14, it must specify appropriate foreground service types. https://developer.android.com/about/versions/14/changes/fgs-types-required
<service android:enabled="true" android:exported="false" android:foregroundServiceType="location" android:name="edu.berkeley.eecs.emission.cordova.tracker.location.TripDiaryStateMachineForegroundService" />
❌ If apps that target Android 14 use a foreground service, they must declare a specific permission, based on the foreground service type, that Android 14 introduces.
❌ ACTIVITY_RECOGNITION permission seems to imply health
as part of the foreground service as well
❌ The best practice for applications starting foreground services is to use the ServiceCompat version of startForeground() (available in androidx-core 1.12 and higher) where you pass in a bitwise integer of foreground service types. You can choose to pass one or more type values.
startForeground
(which converts an existing service to run in the foreground) in one location and startForegroundService
in another, and I don't want to restructure the codepublic static void startForeground(
@NonNull Service service,
int id,
@NonNullnotification,
int foregroundServiceType
)
But the example is
ServiceCompat.startForeground(0, notification, FOREGROUND_SERVICE_TYPE_LOCATION)
Poking around a bit...
Ah! We first call startForegroundService
and then we call startForeground
while starting the service.
https://developer.android.com/develop/background-work/services/foreground-services#java
So we only need to change startForeground
in handleStart
.
While poking around at the documentation related to the foreground service changes in Android 14, (API 34) I also found https://proandroiddev.com/foreground-services-in-android-14-whats-changing-dcd56ad72788 which indicated that the
Starting in Android 14 (API level 34), all long-running workers must be foreground services.
But do we still need that if we have a foreground service for location anyway? I don't think so, given that we have a long-running (always on) foreground service
The type has a 3 minute timeout. A foreground service of this type must be stopped within the timeout by Service.stopSelf(), Context.stopService(android.content.Intent) or their overloads). Service.stopForeground(int) will also work, which will demote the service to a "background" service, which will soon be stopped by the system.
If the service isn't stopped within the timeout, Service.onTimeout(int) will be called. Note, even when the system calls this callback, it will not stop the service automatically. You still need to stop the service using one of the aforementioned ways even when you get this callback.
If the service is still not stopped after the callback, the app will be declared an ANR, after a short grace period of several seconds.
Need to test!
Runtime-registered broadcasts receivers must specify export behavior
Building on the prior investigation into runtime registered broadcasts https://github.com/e-mission/e-mission-docs/issues/1079#issuecomment-2309021838 we need to focus on
plugins//cordova-plugin-em-datacollection/src/android/location/actions/GeofenceActions.java
: Does not need to be exported, since we only need to receive updates from the same appplugins//com.unarin.cordova.beacon/src/android/LocationManager.java
: unsure, given that Some system broadcasts come from highly privileged apps, such as Bluetooth and telephony, that are part of the Android framework but do not run under the system's unique process ID (UID). To receive all system broadcasts, including broadcasts from highly privileged apps, flag your receiver with RECEIVER_EXPORTED.
We are listening to bluetooth, but for the enabled/disabled flags. So it is not clear if that comes from permissions or bluetooth app.
Should test.
Restrictions to implicit and pending intents
So the locations we need to fix are:
plugins//cordova-plugin-em-datacollection/src/android/location/actions/GeofenceLocationIntentService.java
: implicitplugins//cordova-plugin-em-serversync/src/android/ServerSyncAdapter.java
: implicitThe locations we need to test, and potentially fix, are:
plugins//cordova-plugin-file/src/android/LocalFilesystem.java
: broadcastNewFile
is implicit; but broadcasts the intent externallyplugins//cordova-plugin-em-datacollection/src/android/sensors/BatteryUtils.java
: getBatteryInfo
; registering for intentplugins//cordova-plugin-em-datacollection/src/android/location/actions/GeofenceActions.java
: unsureplugins//cordova-plugin-em-datacollection/src/android/verification/SensorControlForegroundDelegate.java
(status screen): implicit, not internalplugins//cordova-plugin-inappbrowser/src/android/InAppBrowser.java
: implicit, not internalplugins//com.unarin.cordova.beacon/src/android/LocationManager.java
: registering for intentplugins//cordova-plugin-local-notification-12/src/android/LocalNotification.java
: implicit, launching externalplugins//cordova-plugin-x-socialsharing/src/android/nl/xservices/plugins/SocialSharing.java
: implicit, not internalOther updates at the end of the issue
Of the remaining issues flagged in https://github.com/e-mission/e-mission-docs/issues/1079#issuecomment-2244192028 the others are either postponeable or not very relevant
The ones we are going to postpone are:
The ones that we will not fix are:
Summary of the 11 points from earlier and their resolution
id | Topic | Resolution |
---|---|---|
1 | Schedule exact alarms are denied by default | Remove permission and change code to use inexact alarms |
2 | Context-registered broadcasts are queued while apps are cached | Need to test to verify that the bluetooth permissions still work |
3 | New reason an app can be placed in the restricted standby bucket | Test out the relevant case |
4 | Foreground service types are required | done |
5 | OpenJDK 17 updates | Already at JDK 17 |
6 | Regional preferences Apps can receive notifications when a user changes their regional preferences and mirror these preferences in app | good idea but not a priority right now. |
7 | Restrictions to implicit and pending intents | Found two implicit intents, that we must fix before the end of the year. |
8 | Runtime-registered broadcasts receivers must specify export behavior | found two locations that seem to be fine wrt exporting, but must test local notifications |
9 | Additional restrictions on starting activities from the background | Not applicable |
10 | Changes to how users experience non-dismissible notifications | Nothing we can do anyway, defer testing |
11 | Data safety information is more visible | Fine by us, nothing to do |
Next steps:
Will test and fix tomorrow!
While trying to rebuild, ran into an issue with loading the dependencies
The dependency is in platforms/android/app/build.gradle
, added as
// SUB-PROJECT DEPENDENCIES START
implementation(project(path: ":CordovaLib"))
implementation "androidx.core:core:1.6.+"
implementation "me.leolin:ShortcutBadger:1.1.22@aar"
implementation "com.google.firebase:firebase-messaging:23.+"
implementation "androidx.webkit:webkit:1.4.0"
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.appcompat:appcompat:1.3.1"
implementation "androidx.legacy:legacy-support-core-utils:1.0.0"
implementation "com.google.code.gson:gson:2.10.1"
implementation "com.google.android.gms:play-services-location:21.0.1"
implementation "androidx.core:core:1.8.0"
implementation "androidx.work:work-runtime:2.7.1"
// SUB-PROJECT DEPENDENCIES END
I looked up the dependency, and the library is here https://mvnrepository.com/artifact/androidx.core/core/1.6.0 and the instructions to include it in gradle are at
// https://mvnrepository.com/artifact/androidx.core/core
runtimeOnly 'androidx.core:core:1.6.0'
The push plugin has "ANDROIDX_CORE_VERSION": "1.6.+"
and the data collection plugin has "ANDROIDX_CORE_VERSION": "1.8.0"
ANDROID_CORE_VERSION
in the push plugin to 1.8.0, the gradle file did not changeimplementation "androidx.core:core:1.6.+"
is now gone; re-testing..., still failsHm... given that this appears to be a common issue with certs that people have encountered before https://stackoverflow.com/questions/69180079/how-to-resolve-gradle-tls-connection-after-upgrading-from-5-4-to-6-8-3 maybe this is a cert issue after all. The CI/CD is working fine.
CI/CD | Our setup |
---|---|
openjdk version "17.0.12" 2024-07-16 |
openjdk 17.0.9 2023-10-17 |
Gradle 8.10, 2024-08-14 11:07:45 UTC |
Gradle 7.6, 2022-11-25 13:35:10 UTC |
Since the cert is in the JRE
You get this message when the JRE is missing a certificate.
Let's try upgrading both of these and see if it fixes the problem.
Did not fix it
> Could not resolve androidx.core:core:1.6.+.
Required by:
project :app
> Failed to list versions for androidx.core:core.
> Unable to load Maven meta-data from https://repo.maven.apache.org/maven2/androidx/core/core/maven-metadata.xml.
> Could not GET 'https://repo.maven.apache.org/maven2/androidx/core/core/maven-metadata.xml'.
> The server may not support the client's requested TLS protocol versions: (TLSv1.2, TLSv1.3). You may need to configure the client to allow other protocols to be used. See: https://docs.gradle.org/7.6/userguide/build_environment.html#gradle_system_properties
> PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Checking the certs installed in the JRE...
Aha! If I go to the missing URL in the browser, I still get the 404 error, but the certificate includes a root that is not part of the standard bundle
and is probably an "enterprise root" https://support.mozilla.org/en-US/kb/how-disable-enterprise-roots-preference?as=u&utm_source=inproduct
Aha! the cert chain is: repo1.maven.org <- netskope.nrel.gov <- NREL CA 01 <- NREL root CA
@louisg1337 you were right that it is due to netskope! I still don't see how this is supposed to work given that the path does not exist, but I just need to figure out how to import the enterprise root into the cacerts
So I tried to look up the roots in multiple ways:
We ended up with multiple copies of the same root key in the cacert (nrelrootca
, nrelrootcabrowser
, nrelrootcakeychain
) but I still get the same error.
Note also that the error trace has
> The server may not support the client's requested TLS protocol versions: (TLSv1.2, TLSv1.3). You may need to configure the client to allow other protocols to be used. See: https://docs.gradle.org/7.6/userguide/build_environment.html#gradle_system_properties
> PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
while the examples on stackoverflow have
> sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
> PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
> unable to find valid certification path to requested target
Note the lack of TLS 1.3. Maybe the issue is that the netskope routing puts in TLS 1.3 somewhere along the way, while CI/CD goes out to the internet directly.
Note also that even after I installed gradle 8.10
, the build is still using gradle 7.1...
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.6/userguide/command_line_interface.html#sec:command_line_warnings
The gradle version is associated with the cordova version because the gradle files are automatically created by cordova. We have to bump up to the most recent version of cordova-android and cordova-ios anyway; let's do that and see if it fixes the problem. Note that the most recent version of cordova-android uses gradle 8.7
Upgrading to cordova-android@13.0.0 https://cordova.apache.org/announcements/2024/05/23/cordova-android-13.0.0.html
Bingo! That worked!
Per the instructions, we need to have SDK Platform 34
and SDK Build Tools 34.0.0
. Which we do.
Older build tools version can be uninstalled if older versions of cordova-android is no longer used in your projects.
This is interesting because removing the older platforms may fix our issues with the SDK install CI/CD task, which is failing because of lack of space. Let's try doing that and see if the build still works...
+ '[' '!' -d /tmp/new-install/Android/sdk/emulator ']'
+ '[' '!' -d /tmp/new-install/Android/sdk/build-tools ']'
+ exit 1
New SDK root /tmp/new-install/Android/sdk
total 8
drwxr-xr-x 8 runner wheel 256 Jul 14 04:36 .
drwxr-xr-x 3 runner wheel 96 Jul 14 04:27 ..
-rw-r--r-- 1 runner wheel 16 Jul 14 04:36 .knownPackages
drwxr-xr-x 2 runner wheel 64 Jul 14 04:36 .temp
drwxr-xr-x 3 runner wheel 96 Jul 14 04:27 cmdline-tools
drwxr-xr-x 29 runner wheel 928 Jul 14 04:27 emulator
drwxr-xr-x 5 runner wheel 160 Jul 14 04:27 licenses
drwxr-xr-x 14 runner wheel 448 Jul 14 04:35 system-images
Error: Process completed with exit code 1.
Note that the minSDK is now 24 (Android 7). This has not changed since the last release (https://cordova.apache.org/announcements/2023/05/22/cordova-android-12.0.0.html), but it does mean that we don't need system images for API 22 and 23.
Similarly upgrading the iOS version to 7.1.1 Changes needed:
privacy-manifest
https://cordova.apache.org/announcements/2024/04/03/cordova-ios-7.1.0.htmlFailed with
clang: error: SDK does not contain 'libarclite' at the path '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a'; try increasing the minimum deployment target
This is because although we overwrite the IPHONEOS_DEPLOYMENT_TARGET
in a hook (consistent with https://github.com/e-mission/e-mission-phone/pull/1149), and right after the hook, we only see that target, others get added later. Looking at the file, it looks like there are multiple copies of the target. Let's delete everything and see if it helps.
Did not help. I wonder if this is related to "Moved CODE_SIGN_ENTITLEMENTS to the target settings of the application target within the Xcode project."
Upgrading to the most recent version of the cordova CLI fixed it. Looking through the other upgrades that are relevant to us: ⬆️ cordova@12.0.0 ✔️ file@8.0.0 🚫 media-capture 👍 cordova-android@12.0.1 👍 cordova-ios@7.0.1 🚫 camera, media, file-transfer 🚫 geolocation ⬆️ in-app-browser@6.0.0 🚫 electron 👍 cordova-ios@7.1.0 ⬆️ cordova-android@13.0.0 ⬆️ cordova-ios@7.1.1
Let's bump these up and also bump up nvm (0.40.0), node (20.9.0) and npm (10.8.2) to their LTS versions. Worked!
Note also that the gradle version is automatically configured and downloaded by cordova https://github.com/e-mission/e-mission-docs/issues/1079#issuecomment-2310740124 so I don't think we need to have it installed via sdkman
Let's try removing that and see if it works. Worked! Let's pause here for a second and get these basic changes pushed.
Geofence Action intent, improve security
This is a bit tricky because of the way in which we have structured the code. We launch the GeofenceLocationIntentService service through an explicit intent. When we get the location, we want to get it back here, and then modify the location field and have the geofence action continue. So we register a BroadcastReceiver as an anonymous inner class. Right now, we send an implicit intent and filter by it in the broadcast receiver.
So the flow is: we receive location, we broadcast location, we receive location, we modify GeofenceActions fields. To make this an explicit intent, we need to:
$1
) LocalBroadcastManager.getInstance(mCtxt).registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(mCtxt, TAG, "recieved broadcast intent "+intent);
synchronized(GeofenceActions.this) {
GeofenceActions.this.newLastLocation = intent.getParcelableExtra(GeofenceLocationIntentService.INTENT_RESULT_KEY);
GeofenceActions.this.notify();
}
}
}, new IntentFilter(GeofenceLocationIntentService.INTENT_NAME));
Let's try to determine the anonymous class name by printing it out (Log.i(mCtxt, TAG, "recieved broadcast intent "+intent+" in class "+getClass().getName());
). After restoring the old intent, we get
08-27 19:51:42.147 20451 20451 I CreateGeofenceAction: recieved broadcast intent Intent
{ act=GEOFENCE_LOCATION_RESULT (has extras) } in class edu.berkeley.eecs.emission.cordov
a.tracker.location.actions.GeofenceActions$1
There is also this argument that if you just need to notify one particular class, we should not use a receiver.
https://stackoverflow.com/questions/4134203/how-to-use-registerreceiver-method
I am using this pattern to ensure loose coupling - there is also not really a mechanism to pass in the GeofenceActions
object to the service. We can, of course, also refactor to not require a broadcast; maybe using a singleton, or converting GeofenceActions
to a service that we can communicate with the other service or passing in the GeofenceActions
as an object to the pending intent (if such as thing is possible).
But I am not going to tackle that more complex restructuring now.
Instead, I will just make the changes to address the security best practices https://developer.android.com/develop/background-work/background-tasks/broadcasts#java
LocalBroadcastManager
to ContextCompat.registerReceiver
But note that registerReceiver
was added in 1.9.0 and our current version is 1.8.0.
package.json
and package.cordovabuild.json`And it still failed
08-27 23:16:16.852 24596 27052 D CreateGeofenceAction: About to start waiting for locati
08-27 23:16:20.588 24596 24596 D GeofenceLocationIntentService: onCreate called
08-27 23:16:20.709 24596 27083 I GeofenceLocationIntentService: broadcasting intent Intent {act=GEOFENCE_LOCATION_RESULT pkg=edu.berkeley.eecs.emission (has extras) }
08-27 23:16:20.722 24596 24596 D GeofenceLocationIntentService: onDestroy called
...
08-27 23:16:21.576 24596 24596 D GeofenceLocationIntentService: onCreate called
...
08-27 23:16:21.670 24596 27089 I GeofenceLocationIntentService: broadcasting intent Intent { act=GEOFENCE_LOCATION_RESULT pkg=edu.berkeley.eecs.emission (has extras) }
08-27 23:16:21.679 24596 24596 D GeofenceLocationIntentService: onDestroy called
...
08-27 23:16:22.582 24596 24596 D GeofenceLocationIntentService: onCreate called
....
08-27 23:16:22.672 24596 27103 I GeofenceLocationIntentService: broadcasting intent Inte
nt { act=GEOFENCE_LOCATION_RESULT pkg=edu.berkeley.eecs.emission (has extras) }
08-27 23:16:22.680 24596 24596 D GeofenceLocationIntentService: onDestroy called
Since I can't figure out why the ContextCompat doens't work:
Note also that if the ContextCompat
does not work, we can't actually change any of the LocalBroadcastManager instances to ContextCompat.
https://github.com/e-mission/e-mission-docs/issues/1079#issuecomment-2309319107
The one in the Bluetooth code is actually not a local broadcast receiver
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
cordova.getActivity().registerReceiver(broadcastReceiver, filter);
Rooting the emulator using the instructions at: https://proandroiddev.com/root-an-android-emulator-avd-9f912328ca08 https://gitlab.com/newbit/rootAVD
Find and kill only the foreground service
$ ./adb shell dumpsys activity service edu.berkeley.eecs.emission
$ ./adb shell
emu64xa:/ $
emu64xa:/ # am stopservice edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineForegroundService
Stopping service: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineForegroundService }
Service stopped
emu64xa:/ # dumpsys activity service edu.berkeley.eecs.emission
SERVICE edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineService c5b3d96 pid=(not running)
Turned Bluetooth on/off, no logs (kind of expected, because with the foreground service killed, the one service is not even running).
Launched the app
08-28 09:13:12.752 549 888 W BatteryExternalStatsWorker: error reading Bluetooth stats: 11
08-28 09:14:34.953 10530 10530 D com.unarin.beacon: Bluetooth Service state changed from
STATE_ON to STATE_TURNING_OFF
08-28 09:14:34.956 10530 10530 D com.unarin.beacon: Bluetooth Service state changed from
STATE_TURNING_OFF to STATE_OFF
Try again - Bluetooth is off
$ ./adb shell dumpsys activity service edu.berkeley.eecs.emission
SERVICE edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineForegroundService 6b77a2c pid=10530 user=0
Client:
nothing to dump
SERVICE edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineService c5b3d96 pid=10530 user=0
Client:
nothing to dump
SERVICE edu.berkeley.eecs.emission/org.chromium.content.app.SandboxedProcessService0:0 2139204 pid=10600 user=0
Client:
Failure while dumping the service: java.io.IOException: Timeout
Kill the foreground service
$ ./adb shell
emu64xa:/ $ su
ordova.tracker.location.TripDiaryStateMachineForegroundService <
Stopping service: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineForegroundService }
Service stopped
255|emu64xa:/ # dumpsys activity service edu.berkeley.eecs.emission
SERVICE edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineService c5b3d96 pid=14309 user=0
Client:
Failure while dumping the service: java.io.IOException: Timeout
SERVICE edu.berkeley.eecs.emission/.cordova.tracker.location.actions.GeofenceLocationIntentService 480fa7e pid=14309 user=0
Client:
*** SERVICE 'activity' DUMP TIMEOUT (10000ms) EXPIRED ***
*** SERVICE 'activity' DUMP TIMEOUT (10000ms) EXPIRED ***
dumpsys activity service edu.berkeley.eecs.emission <
SERVICE edu.berkeley.eecs.emission/.cordova.tracker.location.TripDiaryStateMachineService c5b3d96 pid=14309 user=0
Client:
Failure while dumping the service: java.io.IOException: Timeout
emu64xa:/ #
Launch app, no bluetooth updates
$ grep Bluetooth /tmp/logcat.log
08-28 09:29:04.405 18792 18792 D PluginManager: startupPlugins: put - BluetoothClassicSerial
08-28 09:29:04.425 18792 18870 W cr_media: registerBluetoothIntentsIfNeeded: Requires BLUETOOTH permission
Change bluetooth toggle
08-28 09:29:51.699 19355 19387 I bt_bta_dm: packages/modules/Bluetooth/system/bta/dm/bta_dm_act.cc:3153 bta_dm_set_eir: Generating extended inquiry response packet EIR
08-28 09:29:51.699 19355 19387 E bt_btif : packages/modules/Bluetooth/system/main/bte_logmsg.cc:105 LogMsg: toggleProfile: Unknown service 255 being enabled
08-28 09:29:51.734 549 1504 I MediaSessionStack: addSession to bottom of stack | record: com.google.android.bluetooth/BluetoothMediaBrowserService (userId=0)
08-28 09:29:52.043 18792 18792 D com.unarin.beacon: Bluetooth Service state changed from STATE_TURNING_ON to STATE_ON
08-28 09:29:52.059 1353 2658 D BluetoothAdapter: isLeEnabled(): ON
08-28 09:29:52.063 1353 2658 D BluetoothAdapter: isLeEnabled(): ON
08-28 09:29:52.064 1353 4086 I NearbySharing: (REDACTED) Bluetooth is %s
08-28 09:29:52.070 1353 1798 D BluetoothLeScanner: onScannerRegistered() - status=0 scannerId=1 mScannerId=0
08-28 09:29:52.090 19355 19420 I bt_btif : packages/modules/Bluetooth/system/btif/src/bluetooth.cc:829 get_profile_interface: get_profile_interface: id = activity_attribution
08-28 09:29:52.105 19355 19392 I bluetooth: packages/modules/Bluetooth/system/gd/hci/le_scanning_manager.cc:588 stop_scan: Scanning already stopped, return!
08-28 09:29:52.109 19355 19392 I bluetooth: packages/modules/Bluetooth/system/gd/hci/le_address_manager.cc:175 register_client: Scheduled address rotation for first client registered
So we are not going to change this behavior now.
The manifest-registered receivers are not subject to this change
Manifest-declared broadcasts aren't queued, and apps are removed from the cached state for broadcast delivery.
So we don't need to change them. For the record, only these two receivers don't have the exported tag, and they are from a plugin that we haven't forked.
<receiver android:name="com.adobe.phonegap.push.BackgroundActionButtonHandler" />
<receiver android:name="com.adobe.phonegap.push.PushDismissedHandler" />
So I think we are done here.
Now that we have upgraded the base platforms and plugins, we can actually start the code changes outlined in https://github.com/e-mission/e-mission-docs/issues/1079#issuecomment-2309468607
id | Topic | Resolution |
Before fix |
After fix |
---|---|---|---|---|
1 | Schedule exact alarms are denied by default | Remove permission and change code to use inexact alarms | Generates notification (because we are on the exemption list "Apps that are on the power allowlist"). Still want to change this because we don't need the exact alarms, and we might as well lower power consumption, but now the test will just be that we don't crash with the new code | Local notifications are generated and don't crash while either clicking or clearing |
2 | Context-registered broadcasts are queued while apps are cached | we have a foreground service, so are typically not going to be cached. need to test behavior when foreground service is killed, unclear how we can fix other than making the broadcasts manifest-registered | Bluetooth changes are captured when the foreground service is running. They are not captured when the service is not running. They are not queued or delivered when app restarts | Unchanged |
4 | Foreground service types are required | Added the appropriate permissions | App crashes on launch with error Caused by: java.lang.SecurityException: Starting FGS with type location requires permissions: all of the permissions allOf=true [android.permission.FOREGROUND_SERVICE_LOCATION]... |
App does not crash, foreground service is visible |
7 | Restrictions to implicit and pending intents | Found two implicit intents | (1) Crashes with java.lang.RuntimeException: Unable to start activity ComponentInfo{ edu.berkeley.eecs.emission/ de.appplant.cordova.plugin.localnotification.ClickReceiver }: ... to create a new PendingIntent with an implicit Intent use FLAG_IMMUTABLE. , (2) Two existing locations - server sync and geofence location check - continue to work. Trying to get two security improvements: (1) specifying the package in the intent, and creating a non-exported receiver using ContextCompat instead of LocalBroadcastManager |
(1) Removed server sync broadcast and changed the server impl to a NOP, (2) added package to geofence location intent for better security. Changing to ContextCompat caused the receiver to never receive broadcasts, so reverted it |
8 | Runtime-registered broadcasts receivers must specify export behavior | found two locations that seem to be fine wrt exporting, but must test local notifications | local notification works. Using ContextCompat for the new exporting functionality does not appear to work (as tested with the geofence action broadcast) |
code is unchanged |
Next steps:
This is not actually closed.
While testing against the committed code, I didn't want to edit it to force reading the location again as in https://github.com/e-mission/e-mission-docs/issues/1079#issuecomment-2314436185
So I just turned the GPS off in the emulator
Note that this looks like it also provides an explanation for why we see multiple exit activity actions and multiple geofences sometimes.
Logs: logcat.log.gz
This version (1.8.3) is now live on the android and iOS stores. Note that since we use a foreground service, I had to upload a video to the google play store describing what OpenPATH does, and wait for it to be manually reviewed. But it just got accepted right now.
@jf87 @idillon-sfl @asiripanich @ericafenyo @TTalex @AlirezaRa94 @MaliheTabasi for visibility
It is that time of the year again, and we need to upgrade the native code to the most recent version of the android API by the end of August. We do have some time to do this, but I would ideally like ~ 1 month of testing before it goes to production, so we also don't have that much time. I was hoping that @louisg1337 would be able to tackle it this time, but I am not sure if he has enough bandwidth given the changes needed for the carbon footprint improvements. So I might just have to step up and do it one more time.