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 an arbitrary number of schedules per SIM card #1

Closed
iusmac opened this issue Apr 2, 2024 · 0 comments · Fixed by #24
Closed

Add an arbitrary number of schedules per SIM card #1

iusmac opened this issue Apr 2, 2024 · 0 comments · Fixed by #24

Comments

@iusmac
Copy link
Owner

iusmac commented Apr 2, 2024

No description provided.

@iusmac iusmac linked a pull request Jun 9, 2024 that will close this issue
iusmac added a commit that referenced this issue Aug 11, 2024
* Convert `SIM PIN` preference to a FAB button

* Add the `Add` FAB button

* Drop `Reset` scheduler option

* Bring in alarm card layout from `DeskClock` app for schedule items

* fix(ToolbarDecorator): detect layout direction & set relative padding during measurements

In the previous implementation we attempted to detect layout direction
& set relative padding during construction, which may not always be
ready (e.g., in split-screen), resulting in "LTR" padding whereas it's
actually "RTL".

* Update and remove unused translations

* Import translations

* Fix handling `single-schedule`s

1. When AlarmReceiver triggers the sync of all SIM subscriptions with
   their weekly repeat schedules, it overrides user's preference, i.e
   when the SIM card is expected to be disabled/enabled, but the user
   enabled/disabled it manually, so we want to keep the state within the
   allowed period. Currently, this breaks so-called "single-schedule"s,
   i.e., a schedule that doesn't have an opposite schedule that could
   invert the action.
   Fortunately, in the context of AlarmReceiver, we actually don't need
   to force override user's preference at all, because the alarm will
   always fire in the future, and at some point the
   Last{Act/Deact}-ivatedTime fields of the SIM card that we're
   checking to determine the expected state, will be behind the nearest
   schedule at the moment of synchronization.

2. When schedules of a particular SIM subscription are explicitly
   mutated by the user, we trigger the sync of all SIM subscriptions
   with their weekly repeat schedules. Again, we must override user's
   preference in order for the changes to take effect, but we need to do
   this only for the affected SIM subscription, which makes sense
   logically.
   p.s. The previous approach was literally a "left-over" from the
   "alpha" release and was already an overkill even before the
   "single-schedule" support was added, so it's also a tweak.

* Update README & images
iusmac added a commit that referenced this issue Aug 24, 2024
… request

To reproduce this:
1. Need to unset/disable the PIN code for all SIM cards
2. Assiduously spam the on/off toggle for all SIM cards

The fix consists of two parts:
1. We must separately synchronize the call to setSimState(). The NPE
   happened, because, multiple calls can be performed in parallel (see
   #1 & #30), and since we're only synchronizing the wait()/notifyAll()
   calls, when a requests finishes slightly earlier, it cleans up
   the requests metadata written by the other call.
2. We also want to refrain from handling SIM power state response
   directly inside callback listeners, as it'll likely be executed on
   the main thread, while in some circumstances we can make database
   requests via Room that disallows this and can throw an exception.
   Also, we don't want to do it before the notifyAll() call, since this
   is a potential error-prone issue that can trigger a false-positive
   timeout of the pending request if for some reason it will take too
   long to complete. Instead, we store the request response code in
   globally accessible metadata, then notify the caller and handle the
   response inside the caller's worker thread

#1 D  7SIM.SimListViewModel handleOnSimStateChanged(simEntryId=0,enabled=true).
#2 D  7SIM.TelephonyController setSimState(slotIndex=0,enabled=true,keepDisabledAcrossBoots=false) : In sync block.
#3 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=2024-08-20T15:38 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
#4 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=2,state=ENABLED).
#5 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
#6 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().
#7 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
#8 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=0,state=11).
#9 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=0,state=11).
#10 D  7SIM.TelephonyController handleOnSetSimPowerStateForSlotFinished(resCode=11) : requestMetadata=Bundle[{last_activated_time=-999999999-01-01T00:00, last_deactivated_time=2024-08-20T15:38, subscription=Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=2024-08-20T15:38 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }, keep_disabled_across_boots=true}], requestFailed=false,shouldNotifyAllListeners=true
#11 V  7SIM.SubscriptionsImplLegacy removeOnSimStatusChangedListener().
#12 V  7SIM.SubscriptionsImplLegacy unregisterCarrierConfigChangedReceiver().

#13 D  7SIM.DirectBootAwareBroadcastReceiver onReceive() : intent=Intent { act=android.telephony.action.CARRIER_CONFIG_CHANGED flg=0x15000010 cmp=com.github.iusmac.sevensim/.DirectBootAwareBroadcastReceiver (has extras) }
#14 D  7SIM.ForegroundService onCreate().
#15 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SUBSCRIPTIONS_CHANGED cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=1).
#16 D  7SIM.ForegroundService Worker.execute(taskId=1) Add : mQueueSize=0.
#17 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SYNC_SUBSCRIPTION_ENABLED_STATE cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=2).
#18 D  7SIM.ForegroundService Worker.execute(taskId=1) Start : mQueueSize=1.
#19 D  7SIM.ForegroundService Worker.execute(taskId=2) Add : mQueueSize=1.
#20 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_UPDATE_NEXT_WEEKLY_REPEAT_SCHEDULE_PROCESSING_ITER cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=3).
#21 D  7SIM.ForegroundService Worker.execute(taskId=3) Add : mQueueSize=2.
#22 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-20T15:38:51.853) : Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },currentSubState=ENABLED,expectedSubState=UNKNOWN,existsInUsableList=false.
#23 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=ENABLED).
#24 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-20T15:38:51.853) : Subscription { id=2 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=2024-08-20T15:38 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }.
#25 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=2 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
#26 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=2,state=UNKNOWN).
#27 D  7SIM.ForegroundService Worker.execute(taskId=1) Finish : mQueueSize=2.
#28 D  7SIM.ForegroundService Worker.execute(taskId=2) Start : mQueueSize=2.
#29 D  7SIM.SubscriptionScheduler syncSubscriptionEnabledState(subId=1,compareTime=2024-08-20T15:38:51.853,overrideUserPreference=false) : Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },nearestEnableTime=Optional[2024-08-20T14:30],nearestDisableTime=Optional[2024-08-20T18:30],expectedEnabled=false,isInCall=false.
#30 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=false,keepDisabledAcrossBoots=false) : In sync block.
#31 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=1 simState=DISABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=2024-08-20T15:38 keepDisabledAcrossBoots=false }).
#32 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=DISABLED).
#33 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
#34 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().

#35 D  7SIM.SimListViewModel handleOnSimStateChanged(simEntryId=1,enabled=false).
#36 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=false,keepDisabledAcrossBoots=true) : In sync block.
#37 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
#38 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=1,state=1).
#39 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=1,state=1).
#40 E  AndroidRuntime Process: com.github.iusmac.sevensim, PID: 2426
#41 E  AndroidRuntime java.lang.RuntimeException: Error receiving broadcast Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) } in com.github.iusmac.sevensim.telephony.Subscriptions$1@a222e8c
#42 E  AndroidRuntime Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.github.iusmac.sevensim.telephony.Subscription.getSlotIndex()' on a null object reference
#43 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.TelephonyController$SimStatusChangedListener.onSimStatusChanged(TelephonyController.java:372)
#44 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.Subscriptions.dispatchOnSimStatusChanged(Subscriptions.java:446)
#45 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.Subscriptions.-$$Nest$mdispatchOnSimStatusChanged(Unknown Source:0)
#46 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.Subscriptions$1.onReceive(Subscriptions.java:85)
#47 I  am_crash [2426,0,com.github.iusmac.sevensim,550026951,java.lang.NullPointerException,Attempt to invoke virtual method 'int com.github.iusmac.sevensim.telephony.Subscription.getSlotIndex()' on a null object reference,TelephonyController.java,372]

Signed-off-by: iusmac <iusico.maxim@libero.it>
iusmac added a commit that referenced this issue Aug 24, 2024
To reproduce this:
1. Ensure the device is using the legacy radio interface layer (RIL) to
   control SIM cards
2. Toggle the same SIM card multiple times in a row
3. Observe the SIM card forcefully returning to its original state due
   to the synchronization with its schedules

Deep-dive explanation:
When performing the SIM subscription state mutation for the same SIM
card multiple times in a row (#1-12 & #13-24), this will sooner trigger
in parallel the global carrier config changed event listener (#25),
which in turn will run the SIM subscriptions sync process. In this case,
the SIM subscriptions sync process may short-circuit and terminate fast,
or it may force override user's preference applied a moment ago through
the scheduler (#41). This is because the last{Activated/Deactivated}Time
fields used to determine whether to keep the user's preference within
the allowed period or not was reset during the SIM subscriptions sync
process, since the SIM subscription can be temporarily unavailable (#38)
during state transition.

The fix:
This patch fix introduces an atomic flag to block the synchronization of the
internal state of all SIM subscriptions during SIM subscription state
mutations.
Currently, this issue affects heavily only devices using legacy RIL, but
we'll use the flag on the newer RIL too, since there's a call to the
database that may take longer to complete in some circumstances.

#1 D  7SIM.SimListViewModel handleOnSimEnabledStateChanged(simEntryId=1,enabled=false).
#2 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=false,keepDisabledAcrossBoots=true) : In sync block.
#3 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=1 simState=DISABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=2024-08-23T14:51 keepDisabledAcrossBoots=true }).
#4 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=DISABLED).
#5 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
#6 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().
#7 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
#8 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=1,state=1).
#9 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=1,state=1).
#10 V  7SIM.SubscriptionsImplLegacy removeOnSimStatusChangedListener().
#11 V  7SIM.SubscriptionsImplLegacy unregisterCarrierConfigChangedReceiver().
#12 D  7SIM.TelephonyController handleOnSetSimPowerStateForSlotFinished(resCode=1) : requestMetadata=Bundle[{last_activated_time=-999999999-01-01T00:00, last_deactivated_time=2024-08-23T14:51, subscription=Subscription { id=1 slotIndex=1 simState=DISABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=2024-08-23T14:51 keepDisabledAcrossBoots=true }, keep_disabled_across_boots=true}], requestFailed=false,shouldNotifyAllListeners=false

#13 D  7SIM.SimListViewModel handleOnSimEnabledStateChanged(simEntryId=1,enabled=true).
#14 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=true,keepDisabledAcrossBoots=false) : In sync block.
#15 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=2024-08-23T14:51 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
#16 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=ENABLED).
#17 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
#18 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().
#19 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
#20 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=1,state=11).
#21 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=1,state=11).
#22 V  7SIM.SubscriptionsImplLegacy removeOnSimStatusChangedListener().
#23 V  7SIM.SubscriptionsImplLegacy unregisterCarrierConfigChangedReceiver().
#24 D  7SIM.TelephonyController handleOnSetSimPowerStateForSlotFinished(resCode=11) : requestMetadata=Bundle[{last_activated_time=2024-08-23T14:51, last_deactivated_time=-999999999-01-01T00:00, subscription=Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=2024-08-23T14:51 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }, keep_disabled_across_boots=false}], requestFailed=false,shouldNotifyAllListeners=true

#25 D  7SIM.DirectBootAwareBroadcastReceiver onReceive() : intent=Intent { act=android.telephony.action.CARRIER_CONFIG_CHANGED flg=0x15000010 cmp=com.github.iusmac.sevensim/.DirectBootAwareBroadcastReceiver (has extras) }
#26 D  7SIM.ForegroundService onCreate().
#27 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SUBSCRIPTIONS_CHANGED cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=1).
#28 D  7SIM.ForegroundService Worker.execute(taskId=1) Add : mQueueSize=0.
#29 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SYNC_SUBSCRIPTION_ENABLED_STATE cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=2).
#30 D  7SIM.ForegroundService Worker.execute(taskId=1) Start : mQueueSize=1.
#31 D  7SIM.ForegroundService Worker.execute(taskId=2) Add : mQueueSize=1.
#32 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_UPDATE_NEXT_WEEKLY_REPEAT_SCHEDULE_PROCESSING_ITER cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=3).
#33 D  7SIM.ForegroundService Worker.execute(taskId=3) Add : mQueueSize=2.
#34 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-23T14:51:08.280) : Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },currentSubState=ENABLED,expectedSubState=UNKNOWN,existsInUsableList=false.
#35 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=2,state=ENABLED).
#36 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-23T14:51:08.280) : Subscription { id=1 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=2024-08-23T14:51 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }.
#37 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
#38 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=UNKNOWN).
#39 D  7SIM.ForegroundService Worker.execute(taskId=1) Finish : mQueueSize=2.
#40 D  7SIM.ForegroundService Worker.execute(taskId=2) Start : mQueueSize=2.
#41 D  7SIM.SubscriptionScheduler syncSubscriptionEnabledState(subId=2,compareTime=2024-08-23T14:51:08.280,overrideUserPreference=false) : Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },nearestEnableTime=Optional.empty,nearestDisableTime=Optional[2024-08-19T08:00],expectedEnabled=false,isInCall=false.
#42 D  7SIM.TelephonyController setSimState(slotIndex=0,enabled=false,keepDisabledAcrossBoots=false) : In sync block.

Signed-off-by: iusmac <iusico.maxim@libero.it>

# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# Date:      Fri Aug 23 16:04:50 2024 +0200
#
# interactive rebase in progress; onto 7db7f56
# Last command done (1 command done):
#    edit 42ea1228 fix(telephony): prevent SIM subscriptions sync when altering SIM state
# Next command to do (1 remaining command):
#    exec GIT_AUTHOR_NAME='iusmac' GIT_AUTHOR_EMAIL='iusico.maxim@libero.it' GIT_AUTHOR_DATE='Fri Aug 23 16:04:50 2024 +0200' GIT_COMMITTER_NAME='iusmac' GIT_COMMITTER_EMAIL='iusico.maxim@libero.it' GIT_COMMITTER_DATE='Fri Aug 23 16:04:50 2024 +0200' git commit --quiet --amend --reset-author --no-edit
# You are currently editing a commit while rebasing branch '14.0-dev' on '7db7f568'.
#
# Changes to be committed:
#	modified:   src/com/github/iusmac/sevensim/telephony/SubscriptionController.java
#	modified:   src/com/github/iusmac/sevensim/telephony/Subscriptions.java
#	modified:   src/com/github/iusmac/sevensim/telephony/TelephonyController.java
#
iusmac added a commit that referenced this issue Aug 24, 2024
… request

To reproduce this:
1. Need to unset/disable the PIN code for all SIM cards
2. Assiduously spam the on/off toggle for all SIM cards

The fix consists of two parts:
1. We must separately synchronize the call to setSimState(). The NPE
   happened, because, multiple calls can be performed in parallel (see
   #1 & #30), and since we're only synchronizing the wait()/notifyAll()
   calls, when a requests finishes slightly earlier, it cleans up
   the requests metadata written by the other call.
2. We also want to refrain from handling SIM power state response
   directly inside callback listeners, as it'll likely be executed on
   the main thread, while in some circumstances we can make database
   requests via Room that disallows this and can throw an exception.
   Also, we don't want to do it before the notifyAll() call, since this
   is a potential error-prone issue that can trigger a false-positive
   timeout of the pending request if for some reason it will take too
   long to complete. Instead, we store the request response code in
   globally accessible metadata, then notify the caller and handle the
   response inside the caller's worker thread

1 D  7SIM.SimListViewModel handleOnSimStateChanged(simEntryId=0,enabled=true).
2 D  7SIM.TelephonyController setSimState(slotIndex=0,enabled=true,keepDisabledAcrossBoots=false) : In sync block.
3 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=2024-08-20T15:38 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
4 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=2,state=ENABLED).
5 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
6 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().
7 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
8 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=0,state=11).
9 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=0,state=11).
10 D  7SIM.TelephonyController handleOnSetSimPowerStateForSlotFinished(resCode=11) : requestMetadata=Bundle[{last_activated_time=-999999999-01-01T00:00, last_deactivated_time=2024-08-20T15:38, subscription=Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=2024-08-20T15:38 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }, keep_disabled_across_boots=true}], requestFailed=false,shouldNotifyAllListeners=true
11 V  7SIM.SubscriptionsImplLegacy removeOnSimStatusChangedListener().
12 V  7SIM.SubscriptionsImplLegacy unregisterCarrierConfigChangedReceiver().

13 D  7SIM.DirectBootAwareBroadcastReceiver onReceive() : intent=Intent { act=android.telephony.action.CARRIER_CONFIG_CHANGED flg=0x15000010 cmp=com.github.iusmac.sevensim/.DirectBootAwareBroadcastReceiver (has extras) }
14 D  7SIM.ForegroundService onCreate().
15 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SUBSCRIPTIONS_CHANGED cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=1).
16 D  7SIM.ForegroundService Worker.execute(taskId=1) Add : mQueueSize=0.
17 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SYNC_SUBSCRIPTION_ENABLED_STATE cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=2).
18 D  7SIM.ForegroundService Worker.execute(taskId=1) Start : mQueueSize=1.
19 D  7SIM.ForegroundService Worker.execute(taskId=2) Add : mQueueSize=1.
20 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_UPDATE_NEXT_WEEKLY_REPEAT_SCHEDULE_PROCESSING_ITER cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=3).
21 D  7SIM.ForegroundService Worker.execute(taskId=3) Add : mQueueSize=2.
22 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-20T15:38:51.853) : Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },currentSubState=ENABLED,expectedSubState=UNKNOWN,existsInUsableList=false.
23 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=ENABLED).
24 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-20T15:38:51.853) : Subscription { id=2 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=2024-08-20T15:38 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }.
25 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=2 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
26 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=2,state=UNKNOWN).
27 D  7SIM.ForegroundService Worker.execute(taskId=1) Finish : mQueueSize=2.
28 D  7SIM.ForegroundService Worker.execute(taskId=2) Start : mQueueSize=2.
29 D  7SIM.SubscriptionScheduler syncSubscriptionEnabledState(subId=1,compareTime=2024-08-20T15:38:51.853,overrideUserPreference=false) : Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },nearestEnableTime=Optional[2024-08-20T14:30],nearestDisableTime=Optional[2024-08-20T18:30],expectedEnabled=false,isInCall=false.
30 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=false,keepDisabledAcrossBoots=false) : In sync block.
31 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=1 simState=DISABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=2024-08-20T15:38 keepDisabledAcrossBoots=false }).
32 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=DISABLED).
33 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
34 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().

35 D  7SIM.SimListViewModel handleOnSimStateChanged(simEntryId=1,enabled=false).
36 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=false,keepDisabledAcrossBoots=true) : In sync block.
37 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
38 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=1,state=1).
39 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=1,state=1).
40 E  AndroidRuntime Process: com.github.iusmac.sevensim, PID: 2426
41 E  AndroidRuntime java.lang.RuntimeException: Error receiving broadcast Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) } in com.github.iusmac.sevensim.telephony.Subscriptions$1@a222e8c
42 E  AndroidRuntime Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int com.github.iusmac.sevensim.telephony.Subscription.getSlotIndex()' on a null object reference
43 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.TelephonyController$SimStatusChangedListener.onSimStatusChanged(TelephonyController.java:372)
44 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.Subscriptions.dispatchOnSimStatusChanged(Subscriptions.java:446)
45 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.Subscriptions.-$$Nest$mdispatchOnSimStatusChanged(Unknown Source:0)
46 E  AndroidRuntime      at com.github.iusmac.sevensim.telephony.Subscriptions$1.onReceive(Subscriptions.java:85)
47 I  am_crash [2426,0,com.github.iusmac.sevensim,550026951,java.lang.NullPointerException,Attempt to invoke virtual method 'int com.github.iusmac.sevensim.telephony.Subscription.getSlotIndex()' on a null object reference,TelephonyController.java,372]

Signed-off-by: iusmac <iusico.maxim@libero.it>
iusmac added a commit that referenced this issue Aug 24, 2024
To reproduce this:
1. Ensure the device is using the legacy radio interface layer (RIL) to
   control SIM cards
2. Toggle the same SIM card multiple times in a row
3. Observe the SIM card forcefully returning to its original state due
   to the synchronization with its schedules

Deep-dive explanation:
When performing the SIM subscription state mutation for the same SIM
card multiple times in a row (#1-12 & #13-24), this will sooner trigger
in parallel the global carrier config changed event listener (#25),
which in turn will run the SIM subscriptions sync process. In this case,
the SIM subscriptions sync process may short-circuit and terminate fast,
or it may force override user's preference applied a moment ago through
the scheduler (#41). This is because the last{Activated/Deactivated}Time
fields used to determine whether to keep the user's preference within
the allowed period or not was reset during the SIM subscriptions sync
process, since the SIM subscription can be temporarily unavailable (#38)
during state transition.

The fix:
This patch fix introduces an atomic flag to block the synchronization of the
internal state of all SIM subscriptions during SIM subscription state
mutations.
Currently, this issue affects heavily only devices using legacy RIL, but
we'll use the flag on the newer RIL too, since there's a call to the
database that may take longer to complete in some circumstances.

1 D  7SIM.SimListViewModel handleOnSimEnabledStateChanged(simEntryId=1,enabled=false).
2 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=false,keepDisabledAcrossBoots=true) : In sync block.
3 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=1 simState=DISABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=2024-08-23T14:51 keepDisabledAcrossBoots=true }).
4 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=DISABLED).
5 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
6 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().
7 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
8 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=1,state=1).
9 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=1,state=1).
10 V  7SIM.SubscriptionsImplLegacy removeOnSimStatusChangedListener().
11 V  7SIM.SubscriptionsImplLegacy unregisterCarrierConfigChangedReceiver().
12 D  7SIM.TelephonyController handleOnSetSimPowerStateForSlotFinished(resCode=1) : requestMetadata=Bundle[{last_activated_time=-999999999-01-01T00:00, last_deactivated_time=2024-08-23T14:51, subscription=Subscription { id=1 slotIndex=1 simState=DISABLED iconTint=-4056997 name=Vodafone lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=2024-08-23T14:51 keepDisabledAcrossBoots=true }, keep_disabled_across_boots=true}], requestFailed=false,shouldNotifyAllListeners=false

13 D  7SIM.SimListViewModel handleOnSimEnabledStateChanged(simEntryId=1,enabled=true).
14 D  7SIM.TelephonyController setSimState(slotIndex=1,enabled=true,keepDisabledAcrossBoots=false) : In sync block.
15 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=2024-08-23T14:51 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
16 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=ENABLED).
17 V  7SIM.SubscriptionsImplLegacy addOnSimStatusChangedListener().
18 V  7SIM.SubscriptionsImplLegacy registerCarrierConfigChangedReceiver().
19 V  7SIM.SubscriptionsImplLegacy onReceive() : intent=Intent { act=android.telephony.action.SIM_CARD_STATE_CHANGED flg=0x5000010 (has extras) }
20 V  7SIM.SubscriptionsImplLegacy dispatchOnSimStatusChanged(slotIndex=1,state=11).
21 V  7SIM.TelephonyController onSimStatusChanged(slotIndex=1,state=11).
22 V  7SIM.SubscriptionsImplLegacy removeOnSimStatusChangedListener().
23 V  7SIM.SubscriptionsImplLegacy unregisterCarrierConfigChangedReceiver().
24 D  7SIM.TelephonyController handleOnSetSimPowerStateForSlotFinished(resCode=11) : requestMetadata=Bundle[{last_activated_time=2024-08-23T14:51, last_deactivated_time=-999999999-01-01T00:00, subscription=Subscription { id=1 slotIndex=1 simState=ENABLED iconTint=-4056997 name=Vodafone lastActivatedTime=2024-08-23T14:51 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }, keep_disabled_across_boots=false}], requestFailed=false,shouldNotifyAllListeners=true

25 D  7SIM.DirectBootAwareBroadcastReceiver onReceive() : intent=Intent { act=android.telephony.action.CARRIER_CONFIG_CHANGED flg=0x15000010 cmp=com.github.iusmac.sevensim/.DirectBootAwareBroadcastReceiver (has extras) }
26 D  7SIM.ForegroundService onCreate().
27 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SUBSCRIPTIONS_CHANGED cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=1).
28 D  7SIM.ForegroundService Worker.execute(taskId=1) Add : mQueueSize=0.
29 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_SYNC_SUBSCRIPTION_ENABLED_STATE cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=2).
30 D  7SIM.ForegroundService Worker.execute(taskId=1) Start : mQueueSize=1.
31 D  7SIM.ForegroundService Worker.execute(taskId=2) Add : mQueueSize=1.
32 D  7SIM.ForegroundService onStartCommand(intent=Intent { act=ACTION_UPDATE_NEXT_WEEKLY_REPEAT_SCHEDULE_PROCESSING_ITER cmp=com.github.iusmac.sevensim/.ForegroundService (has extras) },flags=0,startId=3).
33 D  7SIM.ForegroundService Worker.execute(taskId=3) Add : mQueueSize=2.
34 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-23T14:51:08.280) : Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },currentSubState=ENABLED,expectedSubState=UNKNOWN,existsInUsableList=false.
35 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=2,state=ENABLED).
36 D  7SIM.SubscriptionsImplLegacy syncSubscriptions(dateTime=2024-08-23T14:51:08.280) : Subscription { id=1 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=2024-08-23T14:51 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }.
37 V  7SIM.SubscriptionsImplLegacy persistSubscription(sub=Subscription { id=1 slotIndex=-1 simState=UNKNOWN iconTint=-16777216 name= lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false }).
38 D  7SIM.SubscriptionsImplLegacy persistSubscriptionState(subId=1,state=UNKNOWN).
39 D  7SIM.ForegroundService Worker.execute(taskId=1) Finish : mQueueSize=2.
40 D  7SIM.ForegroundService Worker.execute(taskId=2) Start : mQueueSize=2.
41 D  7SIM.SubscriptionScheduler syncSubscriptionEnabledState(subId=2,compareTime=2024-08-23T14:51:08.280,overrideUserPreference=false) : Subscription { id=2 slotIndex=0 simState=ENABLED iconTint=-13408298 name=Vodafone (work) lastActivatedTime=-999999999-01-01T00:00 lastDeactivatedTime=-999999999-01-01T00:00 keepDisabledAcrossBoots=false },nearestEnableTime=Optional.empty,nearestDisableTime=Optional[2024-08-19T08:00],expectedEnabled=false,isInCall=false.
42 D  7SIM.TelephonyController setSimState(slotIndex=0,enabled=false,keepDisabledAcrossBoots=false) : In sync block.

Signed-off-by: iusmac <iusico.maxim@libero.it>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant