Skip to main content
SA-016 Grade B+ Phase 3

SA-016: Tray Visibility Control and Indicator Suppression Analysis

This analysis documents Facebook's Stories/Snacks tray visibility control system. The investigation reveals a sophisticated system for controlling when the stories tray is visible and how bucket reranking occurs based on visibility state. Key findings include: 1. **Multiple classes control tray visibility** with a coordinated observer/tracker pattern 2. **`_reRankBucketsWhenTrayIsNotVisible`** flag controls whether bucket reranking occurs when tray is hidden 3. **`privacyIndicatorUnit`** is a distinct component tied to feed story actions

Key Findings

Component Status / Finding
FBFeedSecondaryActionButtonTapComponentController 0x0002bb70

Technical Diagrams

Primary Methods Located Line 24
| Address | Class | Method | Description |
|---------|-------|--------|-------------|
| 0x000da4b8 | FBSnacksTrayDeliveryLifecycleTNLHandler | trayVisibilityChangedWithTrayLogInfo:visible: | Main visibility change handler |
| 0x000a94cc | FBSnacksUnifiedQueryController | _setIsTrayVisible: | Internal tray visibility setter |
| 0x00164e4c | FBSnacksTrayActivityTracker | setIsTrayVisible: | Public tray visibility setter |
| 0x0002651c | FBSnacksTrayActivityTracker | isTrayVisible | Visibility getter |
| 0x000da32c | FBSnacksTrayActivityTracker | trayVisibilityChanged: | Visibility change notification |
| 0x001e88b4 | FBSnacksCSRRerankManager | reRankBucketsWithTrayVisibility:viewerIsPresenting:currentTime: | Rerank with visibility |
Reranking-Related Methods Line 35
| Address | Class | Method |
|---------|-------|--------|
| 0x000da3ac | Multiple | reRankBucketsWithTrayActivityTrigger: |
| 0x00516e14 | Multiple | reRankBucketsWithDeltaUpdateTrigger |
| 0x000da38c | Multiple | changeTrayVisibilityConditionForReranking: |
| 0x0066cc24 | Multiple | reRankBucketsUnconditionally |
| 0x002c4498 | FBSnacksCSRUnifiedRerankManager | _reRankBucketsWithTrigger:currentTime: |
**Instance Variables:** Line 165
| Offset | Name | Purpose |
|--------|------|---------|
| 0x01bda678 | _session | Session reference |
| 0x01bda67c | _rerankHandler | Handler for reranking |
| 0x01bda680 | _isTrayVisible | Current visibility state |
| 0x01bda684 | _isViewerPresenting | Viewer presentation state |
| 0x01bda688 | _isTrayScrolledToStartingPosition | Scroll state |
**Instance Variables:** Line 187
| Offset | Name | Purpose |
|--------|------|---------|
| 0x01bbfd9c | _csrConnectionManager | Connection manager |
| 0x01bbfda0 | _session | Session reference |
| 0x01bbfda4 | _reRankBucketsWhenTrayIsNotVisible | **KEY FLAG** - controls hidden reranking |
| 0x01bbfda8 | _rerankRateLimitSec | Rate limiting |
| 0x01bbfdac | _lastRerankDate | Last rerank timestamp |
| 0x01bbfdb0 | _isTrayVisible | Visibility state mirror |
| 0x01bbfdb4 | _isViewerPresenting | Viewer state |
Found in multiple classes: Line 221
| Class | Method Address |
|-------|----------------|
| FBFeedSecondaryActionButtonTapComponent | 0x00c3b06c |
| FBFeedSecondaryActionButtonTapComponentController | 0x0002bb70 |
Found in multiple classes related to stories/snacks: Line 242
| Class | Get Method | Set Method | Ivar Offset |
|-------|------------|------------|-------------|
| FBSnacksSettingsIntentTarget | 0x000237e8 | - | 0x01bd4c7c |
| Unknown (offset 0x01bbf390) | 0x009957e8 | 0x0099214c | 0x01bbf390 |
| Unknown (offset 0x01bbf45c) | 0x009f6ba4 | 0x009f65c0 | 0x01bbf45c |
9. Related Configuration Strings Line 339
| String | Purpose |
|--------|---------|
| story_viewer_privacy_indicator | Privacy indicator config key |
| shouldHideStatusBar | Status bar suppression flag |
| should_hide_nav_bar | Navigation bar suppression |
| should_hide_title | Title suppression |
| should_hide_unit_nav | Unit navigation suppression |

Code Evidence

ARM64
method.FBSnacksUnifiedQueryController._setIsTrayVisible:
    ; Store visibility flag at offset 0x15a from self
    strb w2, [x0, 0x15a]    ; arg3 = visible (bool)

    ; Compare visibility to 0
    cmp w2, 0

    ; Load either 0x1a0 or 0x198 based on visibility
    mov w8, 0x1a0           ; offset when hidden
    mov w9, 0x198           ; offset when visible
    csel x8, x9, x8, ne     ; select based on visibility

    ; Increment counter at selected offset
    ldr x9, [x0, x8]
    add x9, x9, 1
    str x9, [x0, x8]

    ret
ARM64
method.FBSnacksTrayDeliveryLifecycleTNLHandler.trayVisibilityChangedWithTrayLogInfo:visible:
    ; Early return if bit 0 of w4 (visible arg) is zero
    tbz w4, 0, 0xda4c0      ; if (visible == false) goto 0xda4c0
    ret                      ; early return if visible is false

0xda4c0:
    stp x29, x30, [sp, -0x10]!
    bl fcn.00007e3c          ; likely objc_retainAutoreleasedReturnValue
    mov x19, x0
    bl fcn.000a6b48          ; internal processing
    bl fcn.000da500          ; additional processing

    ; Load address of constant string
    adrp x3, 0x13b3000
    add x3, x3, 0x250        ; likely logging tag

    mov x2, x20
    bl QPLMarkerAnnotateSyncOnSession  ; Performance logging
    bl fcn.000da51c
    bl fcn.00013cbc

    ldr w1, [x21, 0x9c]      ; load parameter
    ldrsh w3, [x8, 0x414]    ; load additional parameter
    mov x2, x20
    bl fcn.000116e0
    b QPLMarkerEndOnSession  ; End performance marker
ARM64
method.FBSnacksTrayActivityTracker.trayVisibilityChanged:
    stp x29, x30, [sp, -0x10]!
    bl fcn.00007e3c          ; objc_retainAutoreleasedReturnValue
    mov x19, x0
    strb w2, [x0, 0x18]      ; Store visibility at offset 0x18
    add x20, x0, 0x10
    bl fcn.0006cd7c          ; Process change
    mov x21, x0
    ldrb w2, [x19, 0x18]     ; Reload visibility
    bl fcn.012e5fa4          ; Notify observers
ARM64
method.FBSnacksCSRRerankManager.reRankBucketsWithTrayVisibility:viewerIsPresenting:currentTime:
    stp x29, x30, [sp, -0x10]!
    bl fcn.00007c58          ; Setup
    mov x21, x4              ; currentTime parameter
    mov x22, x3              ; viewerIsPresenting parameter
    mov x23, x2              ; trayVisibility parameter
    mov x20, x0              ; self
    bl fcn.00030ba4          ; Process rerank
    bl fcn.000764e8          ; Additional processing
    bl fcn.012e5fa4          ; Notify
Plain Text
initWithSession:entrypoint:source:shouldHideStatusBar:shouldHideXpostingToIGSetting:dismissWithConfirmedBlock:threadFragment:trayBucketFragment:
initWithSession:withProfilePicUrl:threadFragment:bucketFragment:shouldHideStatusBar:shouldUseMembersOnlyAsDefaultPrivacyModel:
Plain Text
User Action (scroll, tap, etc.)
        |
        v
FBSnacksTrayActivityTracker
  |- setIsTrayVisible: (0x00164e4c)
  |     Stores visibility at offset 0x18
  |
  |- trayVisibilityChanged: (0x000da32c)
        |
        v
FBSnacksUnifiedQueryController
  |- _setIsTrayVisible: (0x000a94cc)
        Stores at offset 0x15a
        Increments counter at 0x198 (visible) or 0x1a0 (hidden)
        |
        v
FBSnacksTrayDeliveryLifecycleTNLHandler
  |- trayVisibilityChangedWithTrayLogInfo:visible: (0x000da4b8)
        Logs via QPL system
        Early return if becoming visible
        Full processing if becoming hidden
        |
        v
FBSnacksCSRRerankManager
  |- changeTrayVisibilityConditionForReranking: (0x000da38c)
  |
  |- IF _reRankBucketsWhenTrayIsNotVisible == true:
  |     |- reRankBucketsWithTrayVisibility:viewerIsPresenting:currentTime: (0x001e88b4)
  |
  v
Bucket reranking occurs (or not, based on flag)
Objective-C
// FBSnacksTrayActivityTracker
- (void)trayVisibilityChanged:(BOOL)visible;
- (BOOL)isTrayVisible;
- (void)setIsTrayVisible:(BOOL)visible;
- (void)viewerWillAppear;
- (void)viewerDidDisappear;

// FBSnacksUnifiedQueryController
- (void)_setIsTrayVisible:(BOOL)visible;

// FBSnacksTrayDeliveryLifecycleTNLHandler
- (void)trayVisibilityChangedWithTrayLogInfo:(id)logInfo visible:(BOOL)visible;

// FBSnacksCSRRerankManager
- (void)changeTrayVisibilityConditionForReranking:(BOOL)visible;
- (void)reRankBucketsWithTrayVisibility:(BOOL)visible
                     viewerIsPresenting:(BOOL)presenting
                            currentTime:(NSTimeInterval)time;

**Agent ID:** SA-016 **Binary:** `./analysis/facebook/345.0/Facebook.app/Frameworks/FBSharedFramework.framework/FBSharedFramework` **Analysis Date:** 2025-12-30 **Status:** Complete


Executive Summary

This analysis documents Facebook's Stories/Snacks tray visibility control system. The investigation reveals a sophisticated system for controlling when the stories tray is visible and how bucket reranking occurs based on visibility state. Key findings include:

    undefined

1. Tray Visibility Method Addresses

Primary Methods Located

AddressClassMethodDescription
0x000da4b8FBSnacksTrayDeliveryLifecycleTNLHandlertrayVisibilityChangedWithTrayLogInfo:visible:Main visibility change handler
0x000a94ccFBSnacksUnifiedQueryController_setIsTrayVisible:Internal tray visibility setter
0x00164e4cFBSnacksTrayActivityTrackersetIsTrayVisible:Public tray visibility setter
0x0002651cFBSnacksTrayActivityTrackerisTrayVisibleVisibility getter
0x000da32cFBSnacksTrayActivityTrackertrayVisibilityChanged:Visibility change notification
0x001e88b4FBSnacksCSRRerankManagerreRankBucketsWithTrayVisibility:viewerIsPresenting:currentTime:Rerank with visibility

Reranking-Related Methods

AddressClassMethod
0x000da3acMultiplereRankBucketsWithTrayActivityTrigger:
0x00516e14MultiplereRankBucketsWithDeltaUpdateTrigger
0x000da38cMultiplechangeTrayVisibilityConditionForReranking:
0x0066cc24MultiplereRankBucketsUnconditionally
0x002c4498FBSnacksCSRUnifiedRerankManager_reRankBucketsWithTrigger:currentTime:

2. Decompilation Results

2.1 _setIsTrayVisible: (FBSnacksUnifiedQueryController @ 0x000a94cc)

ARM64
method.FBSnacksUnifiedQueryController._setIsTrayVisible:
    ; Store visibility flag at offset 0x15a from self
    strb w2, [x0, 0x15a]    ; arg3 = visible (bool)

    ; Compare visibility to 0
    cmp w2, 0

    ; Load either 0x1a0 or 0x198 based on visibility
    mov w8, 0x1a0           ; offset when hidden
    mov w9, 0x198           ; offset when visible
    csel x8, x9, x8, ne     ; select based on visibility

    ; Increment counter at selected offset
    ldr x9, [x0, x8]
    add x9, x9, 1
    str x9, [x0, x8]

    ret

**Analysis:** This method:

    undefined

2.2 trayVisibilityChangedWithTrayLogInfo:visible: (FBSnacksTrayDeliveryLifecycleTNLHandler @ 0x000da4b8)

ARM64
method.FBSnacksTrayDeliveryLifecycleTNLHandler.trayVisibilityChangedWithTrayLogInfo:visible:
    ; Early return if bit 0 of w4 (visible arg) is zero
    tbz w4, 0, 0xda4c0      ; if (visible == false) goto 0xda4c0
    ret                      ; early return if visible is false

0xda4c0:
    stp x29, x30, [sp, -0x10]!
    bl fcn.00007e3c          ; likely objc_retainAutoreleasedReturnValue
    mov x19, x0
    bl fcn.000a6b48          ; internal processing
    bl fcn.000da500          ; additional processing

    ; Load address of constant string
    adrp x3, 0x13b3000
    add x3, x3, 0x250        ; likely logging tag

    mov x2, x20
    bl QPLMarkerAnnotateSyncOnSession  ; Performance logging
    bl fcn.000da51c
    bl fcn.00013cbc

    ldr w1, [x21, 0x9c]      ; load parameter
    ldrsh w3, [x8, 0x414]    ; load additional parameter
    mov x2, x20
    bl fcn.000116e0
    b QPLMarkerEndOnSession  ; End performance marker

**Analysis:** This method:

    undefined

2.3 trayVisibilityChanged: (FBSnacksTrayActivityTracker @ 0x000da32c)

ARM64
method.FBSnacksTrayActivityTracker.trayVisibilityChanged:
    stp x29, x30, [sp, -0x10]!
    bl fcn.00007e3c          ; objc_retainAutoreleasedReturnValue
    mov x19, x0
    strb w2, [x0, 0x18]      ; Store visibility at offset 0x18
    add x20, x0, 0x10
    bl fcn.0006cd7c          ; Process change
    mov x21, x0
    ldrb w2, [x19, 0x18]     ; Reload visibility
    bl fcn.012e5fa4          ; Notify observers

**Analysis:** This method:

    undefined

2.4 reRankBucketsWithTrayVisibility:viewerIsPresenting:currentTime: (FBSnacksCSRRerankManager @ 0x001e88b4)

ARM64
method.FBSnacksCSRRerankManager.reRankBucketsWithTrayVisibility:viewerIsPresenting:currentTime:
    stp x29, x30, [sp, -0x10]!
    bl fcn.00007c58          ; Setup
    mov x21, x4              ; currentTime parameter
    mov x22, x3              ; viewerIsPresenting parameter
    mov x23, x2              ; trayVisibility parameter
    mov x20, x0              ; self
    bl fcn.00030ba4          ; Process rerank
    bl fcn.000764e8          ; Additional processing
    bl fcn.012e5fa4          ; Notify

**Analysis:** This method takes three parameters:

    undefined

3. Class Ownership

FBSnacksTrayActivityTracker (Class 9540)

**Location:** 0x01c8b7a8 **Base Class:** NSObject **Size:** 4489612 bytes

**Instance Variables:**

OffsetNamePurpose
0x01bda678_sessionSession reference
0x01bda67c_rerankHandlerHandler for reranking
0x01bda680_isTrayVisibleCurrent visibility state
0x01bda684_isViewerPresentingViewer presentation state
0x01bda688_isTrayScrolledToStartingPositionScroll state

**Key Methods:**

    undefined

FBSnacksCSRRerankManager (Class 1439)

**Location:** 0x01bed418 **Base Class:** NSObject **Size:** 3985148 bytes

**Instance Variables:**

OffsetNamePurpose
0x01bbfd9c_csrConnectionManagerConnection manager
0x01bbfda0_sessionSession reference
0x01bbfda4_reRankBucketsWhenTrayIsNotVisible**KEY FLAG** - controls hidden reranking
0x01bbfda8_rerankRateLimitSecRate limiting
0x01bbfdac_lastRerankDateLast rerank timestamp
0x01bbfdb0_isTrayVisibleVisibility state mirror
0x01bbfdb4_isViewerPresentingViewer state

FBSnacksUnifiedQueryController (Class 1297)

**Location:** 0x01bea7b8 **Base Class:** NSObject **Size:** 16496136 bytes

Contains the internal `_setIsTrayVisible:` implementation with visibility counters.

FBSnacksTrayDeliveryLifecycleTNLHandler (Class 3414)

**Location:** 0x01c13d48 **Base Class:** NSObject **Size:** 17518036 bytes

Handles the delivery lifecycle including visibility change events with QPL logging.


4. Privacy Indicator System

privacyIndicatorUnit Property

Found in multiple classes:

ClassMethod Address
FBFeedSecondaryActionButtonTapComponent0x00c3b06c
FBFeedSecondaryActionButtonTapComponentController0x0002bb70

**String Reference:** `story_viewer_privacy_indicator` at 0x01eeb2d2

The `privacyIndicatorUnit` is stored as:

    undefined

This appears to be used for displaying privacy indicators in the stories viewer, potentially related to who can see a story.


5. Status Bar Suppression

shouldHideStatusBar Property

Found in multiple classes related to stories/snacks:

ClassGet MethodSet MethodIvar Offset
FBSnacksSettingsIntentTarget0x000237e8-0x01bd4c7c
Unknown (offset 0x01bbf390)0x009957e80x0099214c0x01bbf390
Unknown (offset 0x01bbf45c)0x009f6ba40x009f65c00x01bbf45c

Status Bar Control Methods

Plain Text
initWithSession:entrypoint:source:shouldHideStatusBar:shouldHideXpostingToIGSetting:dismissWithConfirmedBlock:threadFragment:trayBucketFragment:
initWithSession:withProfilePicUrl:threadFragment:bucketFragment:shouldHideStatusBar:shouldUseMembersOnlyAsDefaultPrivacyModel:

These initializers show that status bar hiding is a configurable option passed when creating stories viewer controllers.


6. iOS Version Checking

Version Check Patterns Found

The binary references standard iOS version checking:

    undefined

**No explicit iOS 14 version check was found** in string form. The iOS 14+ orange dot indicator (introduced for camera/microphone access) would be handled at the system level, not by the app directly.


7. Complete Visibility Suppression Chain

Plain Text
User Action (scroll, tap, etc.)
        |
        v
FBSnacksTrayActivityTracker
  |- setIsTrayVisible: (0x00164e4c)
  |     Stores visibility at offset 0x18
  |
  |- trayVisibilityChanged: (0x000da32c)
        |
        v
FBSnacksUnifiedQueryController
  |- _setIsTrayVisible: (0x000a94cc)
        Stores at offset 0x15a
        Increments counter at 0x198 (visible) or 0x1a0 (hidden)
        |
        v
FBSnacksTrayDeliveryLifecycleTNLHandler
  |- trayVisibilityChangedWithTrayLogInfo:visible: (0x000da4b8)
        Logs via QPL system
        Early return if becoming visible
        Full processing if becoming hidden
        |
        v
FBSnacksCSRRerankManager
  |- changeTrayVisibilityConditionForReranking: (0x000da38c)
  |
  |- IF _reRankBucketsWhenTrayIsNotVisible == true:
  |     |- reRankBucketsWithTrayVisibility:viewerIsPresenting:currentTime: (0x001e88b4)
  |
  v
Bucket reranking occurs (or not, based on flag)

8. Key Configuration Points

_reRankBucketsWhenTrayIsNotVisible (Offset 0x01bbfda4)

This boolean flag in FBSnacksCSRRerankManager controls whether story buckets are reranked when the tray is not visible. This is significant because:

    undefined

This flag could be used to:

    undefined

Visibility Change Counting

The counting mechanism in `_setIsTrayVisible:` tracks:

    undefined

This data is likely used for:

    undefined

9. Related Configuration Strings

StringPurpose
story_viewer_privacy_indicatorPrivacy indicator config key
shouldHideStatusBarStatus bar suppression flag
should_hide_nav_barNavigation bar suppression
should_hide_titleTitle suppression
should_hide_unit_navUnit navigation suppression

10. Conclusions

    undefined

Appendix: Method Signatures

Objective-C
// FBSnacksTrayActivityTracker
- (void)trayVisibilityChanged:(BOOL)visible;
- (BOOL)isTrayVisible;
- (void)setIsTrayVisible:(BOOL)visible;
- (void)viewerWillAppear;
- (void)viewerDidDisappear;

// FBSnacksUnifiedQueryController
- (void)_setIsTrayVisible:(BOOL)visible;

// FBSnacksTrayDeliveryLifecycleTNLHandler
- (void)trayVisibilityChangedWithTrayLogInfo:(id)logInfo visible:(BOOL)visible;

// FBSnacksCSRRerankManager
- (void)changeTrayVisibilityConditionForReranking:(BOOL)visible;
- (void)reRankBucketsWithTrayVisibility:(BOOL)visible
                     viewerIsPresenting:(BOOL)presenting
                            currentTime:(NSTimeInterval)time;

Related Reports

Phase 3 Navigation