cph-cachet / carp.sensing-flutter

CARP Mobile Sensing for Flutter, including mobile sensing framework, data backend support, and the CARP mobile sensing app.
MIT License
79 stars 27 forks source link

PeriodicTrigger not working #384

Closed sc00n closed 5 months ago

sc00n commented 5 months ago

When I use a periodic trigger, for device info or weather, it only works once.

Code:

   protocol.addTaskControl(
        PeriodicTrigger(period: Duration(seconds: 5)),
        BackgroundTask()
          ..addMeasure(Measure(type: DeviceSamplingPackage.DEVICE_INFORMATION)),
        phone);

output:

[{"sensorStartTime":1713881380867767,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881380871224,"data":{"__type":"dk.cachet.carp.deviceinformation","platform":"iOS","deviceId":"F5AA8264-19AA-4A03-814B-32943582AA32","hardware":"iPhone11,2","deviceName":"iPhone","deviceManufacturer":"Apple","deviceModel":"iPhone","operatingSystem":"iOS","deviceData":{"systemName":"iOS","isPhysicalDevice":"true","utsname":{"release":"23.4.0","sysname":"Darwin","nodename":"localhost","machine":"iPhone11,2","version":"Darwin Kernel Version 23.4.0: Fri Mar  8 23:30:38 PST 2024; root:xnu-10063.102.14~67/RELEASE_ARM64_T8020"},"model":"iPhone","localizedModel":"iPhone","systemVersion":"17.4.1","name":"iPhone","identifierForVendor":"F5AA8264-19AA-4A03-814B-32943582AA32"}}},
{"sensorStartTime":1713881385864716,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881390863644,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881395863246,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881400863745,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881405864503,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881410863566,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881415863062,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881420863762,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881425863283,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881430862956,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881435862230,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881440862869,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881445862127,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881450862157,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713881455861267,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":4,"taskName":"Task #11","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
]

As you can see it only once actually got the device info. Its the same for weather (where a periodic trigger is actually useful).

This was tested on iOS with

 carp_core: 1.4.1
  carp_mobile_sensing: 1.5.0
  carp_context_package: ^1.5.0

but I also had the problem with previous versions of carp_mobile_sensing (e.g. 1.4.7).

The problem is the same for Android (only the second entry is an actual entry)

[{"sensorStartTime":1713882174808703,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882174811040,"data":{"__type":"dk.cachet.carp.deviceinformation","platform":"Android","deviceId":"TP1A.220624.014","hardware":"qcom","deviceName":"r8q","deviceManufacturer":"samsung","deviceModel":"SM-G780G","operatingSystem":"REL","deviceData":{"product":"r8qeea","supportedAbis":["arm64-v8a","armeabi-v7a","armeabi"],"serialNumber":"unknown","displayMetrics":{"xDpi":409.4320068359375,"widthPx":1080.0,"heightPx":2400.0,"yDpi":406.3999938964844},"supported32BitAbis":["armeabi-v7a","armeabi"],"display":"TP1A.220624.014.G780GXXS8EXC1","type":"user","isPhysicalDevice":true,"version":{"baseOS":"samsung/r8qeea/r8q:13/TP1A.220624.014/G780GXXU6EWH5:user/release-keys","securityPatch":"2024-03-01","sdkInt":33,"release":"13","codename":"REL","previewSdkInt":0,"incremental":"G780GXXS8EXC1"},"systemFeatures":["android.hardware.sensor.proximity","com.samsung.android.sdk.camera.processor","com.samsung.feature.aodservice_v10","com.sec.feature.motionrecognition_service","com.sec.feature.cover.sview","android.hardware.telephony.ims.singlereg","android.hardware.sensor.accelerometer","android.software.controls","android.hardware.faketouch","android.software.telecom","com.samsung.feature.audio_listenback","android.hardware.telephony.subscription","android.hardware.usb.accessory","android.hardware.telephony.data","android.software.backup","android.hardware.touchscreen","android.hardware.touchscreen.multitouch","android.software.print","android.software.activities_on_secondary_displays","com.sec.feature.nfc_authentication_cover","android.hardware.wifi.rtt","com.samsung.feature.SAMSUNG_EXPERIENCE","com.google.android.feature.ACCESSIBILITY_PRELOAD","com.sec.feature.nfc_authentication","android.software.voice_recognizers","android.software.picture_in_picture","android.hardware.fingerprint","com.samsung.android.knox.knoxsdk","android.hardware.sensor.gyroscope","android.hardware.audio.low_latency","android.software.vulkan.deqp.level","android.software.cant_save_state","android.hardware.security.model.compatible","android.hardware.telephony.messaging","com.samsung.feature.device_category_phone","com.samsung.android.nfc.t4temul","android.hardware.telephony.calling","android.hardware.opengles.aep","com.sec.feature.sensorhub","android.hardware.bluetooth","com.samsung.feature.audio_fast_listenback","android.software.window_magnification","android.hardware.telephony.radio.access","android.hardware.camera.autofocus","android.hardware.telephony.gsm","android.hardware.telephony.ims","com.sec.feature.cocktailpanel","android.software.sip.voip","android.hardware.se.omapi.ese","com.sec.feature.saccessorymanager","com.samsung.feature.samsung_experience_mobile","com.samsung.android.camerasdkservice","android.hardware.camera.concurrent","android.hardware.usb.host","android.hardware.audio.output","android.software.verified_boot","android.hardware.camera.flash","android.hardware.camera.front","android.hardware.se.omapi.uicc","android.hardware.strongbox_keystore","android.hardware.screen.portrait","com.google.android.feature.ASI","android.hardware.nfc","com.google.android.feature.TURBO_PRELOAD","com.samsung.feature.ipsgeofence","com.nxp.mifare","android.hardware.sensor.stepdetector","android.software.home_screen","android.hardware.microphone","com.samsung.feature.aremoji.v2","android.software.autofill","com.samsung.android.sdk.camera.processor.effect","android.software.securely_removes_users","android.hardware.bluetooth_le","android.hardware.sensor.compass","android.hardware.touchscreen.multitouch.jazzhand","android.software.app_widgets","android.software.input_methods","android.hardware.sensor.light","android.hardware.vulkan.version","android.software.companion_device_setup","com.google.android.feature.EEA_V2_DEVICE","com.samsung.feature.galaxyfinder_v7","com.sec.feature.wirelesscharger_authentication","android.software.device_admin","android.hardware.wifi.passpoint","android.hardware.camera","android.hardware.screen.landscape","android.hardware.ram.normal","com.samsung.feature.samsungpositioning.snlp","com.samsung.android.authfw","com.samsung.android.api.version.2402","com.samsung.android.api.version.2403","com.samsung.android.api.version.2501","com.samsung.android.api.version.2502","com.samsung.android.api.version.2601","com.samsung.android.api.version.2701","com.samsung.android.api.version.2801","com.samsung.android.api.version.2802","com.samsung.android.api.version.2803","com.samsung.android.api.version.2901","com.samsung.android.api.version.2902","com.samsung.android.api.version.2903","com.samsung.android.api.version.3001","com.samsung.android.api.version.3002","com.samsung.android.api.version.3101","com.samsung.android.api.version.3201","com.samsung.android.api.version.3301","com.sec.feature.cover","android.software.managed_users","com.sec.feature.nsflp","android.software.webview","android.hardware.sensor.stepcounter","android.hardware.camera.capability.manual_post_processing","android.hardware.camera.any","android.hardware.camera.capability.raw","android.hardware.vulkan.compute","android.software.connectionservice","android.hardware.touchscreen.multitouch.distinct","android.hardware.location.network","com.sec.android.secimaging","android.software.cts","android.software.sip","android.hardware.camera.capability.manual_sensor","android.software.app_enumeration","android.hardware.camera.level.full","com.sec.feature.cover.clearsideviewcover","com.sec.feature.usb_authentication","com.google.android.feature.EEA_DEVICE","android.hardware.wifi.direct","android.software.live_wallpaper","com.sec.feature.pocketmode","android.software.ipsec_tunnels","com.google.android.paid.chrome","android.software.freeform_window_management","android.hardware.audio.pro","android.hardware.nfc.hcef","android.hardware.nfc.uicc","com.samsung.feature.support_repair_mode","android.hardware.location.gps","com.samsung.android.camera.deviceinjector","android.software.midi","com.samsung.feature.samsungpositioning","android.hardware.nfc.any","android.hardware.nfc.ese","android.hardware.nfc.hce","android.hardware.hardware_keystore","android.hardware.wifi","android.hardware.location","com.google.android.paid.search","android.hardware.vulkan.level","com.samsung.android.cameraxservice","com.samsung.android.knox.knoxsdk.api.level.33","com.samsung.android.knox.knoxsdk.api.level.34","com.samsung.android.knox.knoxsdk.api.level.35","com.samsung.android.knox.knoxsdk.api.level.36","android.hardware.wifi.aware","android.software.secure_lock_screen","android.hardware.biometrics.face","android.hardware.telephony","com.sec.android.smartface.smart_stay","android.software.file_based_encryption"],"manufacturer":"samsung","tags":"release-keys","supported64BitAbis":["arm64-v8a"],"bootloader":"G780GXXS8EXC1","fingerprint":"samsung/r8qeea/r8q:13/TP1A.220624.014/G780GXXS8EXC1:user/release-keys","host":"SWDK6902","model":"SM-G780G","id":"TP1A.220624.014","brand":"samsung","device":"r8q","board":"kona","hardware":"qcom"}}},
{"sensorStartTime":1713882179808511,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882184806530,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882189809661,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882194810843,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882199808905,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882204810442,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882209810132,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882214809765,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882219810260,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},
{"sensorStartTime":1713882224809024,"data":{"__type":"dk.cachet.carp.triggeredtask","triggerId":2,"taskName":"Task #9","destinationDeviceRoleName":"Primary Phone","control":"Start"}},

I don't have the problem with PeriodicSamplingConfiguration.

bardram commented 5 months ago

It's because the background task executor is never stopped again, and hence cannot be started when already started:

[log] [CAMS INFO] Starting BackgroundTaskExecutor [1007518798] (started)
[log] [CAMS WARNING] Trying to start a BackgroundTaskExecutor but it is already started. Ignoring this.

So - I guess this comes down to semantics; what do we want to happen if we start a task that is already started?

sc00n commented 5 months ago

Maybe restart the task? For me the important thing is that we can do something periodically, such as getting a device/weather measurement.

bardram commented 5 months ago

A way to solve it is to add a duration to the task so it stops automatically after a while:

    protocol.addTaskControl(
        PeriodicTrigger(period: const Duration(seconds: 5)),
        BackgroundTask(duration: const IsoDuration(seconds: 2), measures: [
          Measure(type: DeviceSamplingPackage.DEVICE_INFORMATION)
        ]),
        phone);

But - there are a couple of issues with this too:

  1. using an IsoDuration instead of a regular Dart Duration class seems strange (from a Dart API point-of-view)

  2. using a BackgroundTask for this kind of "on-time" measures seems like a bad design

The issue is that measures both comes as one-time and event-based measures. And the Task controlling the measures needs to be know this - somehow. In this case the DEVICE_INFORMATION is a one-time measure but it is controlled by a BackgroundTask that runs until stopped.

So - will try to address this.

bardram commented 5 months ago

carp_core 1.5.0 released solving item 1 above. Now you can write:

    protocol.addTaskControl(
        PeriodicTrigger(period: const Duration(seconds: 5)),
        BackgroundTask(duration: const Duration(seconds: 2), measures: [
          Measure(type: DeviceSamplingPackage.DEVICE_INFORMATION)
        ]),
        phone);
bardram commented 5 months ago

Anyway - another issue is that according to the definition of a BackgroundTask:

The task runs for the specified [duration], or until stopped, or until all measures and/or outputs have completed.

So - I guess that the implementation of the BackgroundTaskExecutor does not comply to this contract.