Deconstructing One UI – Mapping the Screen Interception and Telemetry inside the Samsung Browser

descriptionStandard

Anyone that that personally knows me also knows I have a slight obsession with battery life optimisations and services running on my devices.

Recently an update to the Samsung browser version 30.0.0.63 (Android) brought about several glaringly obvious issues that impacted my usage and consumed significant battery.

  1. The first issue was in video playback; when ever I would play a video through the browser the audio and video frames would be out of sync. Watching videos with anyone talking their words were out of sync to the video by a few milliseconds this became annoying quickly.
  2. The next issue would be that every few minutes the video would stutter; to be clear here it would briefly pause for a second and then resume, when it resumed it trigger the videos playback overlay. This too quickly grew tedious.
  3. Manual tapping the screen during playback which normally brings up the playback controls would also make the video briefly freeze and stutter.

I did the obvious and attempted to search online about this new release and determine if others were experiencing similar issues I found little of any relevance.

This is article although somewhat long winded explores and exposes a significant tracking services it includes many examples taken straight from my device logs.

Using another browser such as Firefox (which I switched too permanently) I didn’t experience any of these issues; this piqued my curiosity as I’ve previously preferred the Samsung Browser on Android (since the Galaxy note 4…).

As an Android developer myself I decided to delve in to this further to see what’s going on under the hood; what I found is incredibly disturbing.

Utilising Logcat to view the device logs; I found several serious invasions of privacy, data collection including the use of screen mirroring, front camera access, clipboard access, and more all linked to the Samsung account identifier and sent somewhere.

I’ve attached sections from the log dump taken from my S24 Ultra; note that I’ve redacted what I believe to be unique identifiers, tokens and the like. Though there is a chance I’ve missed some (which doesn’t really matter as I will soon be ditching this device and brand).

Lets get started with this log snippet:

06-23 19:24:58.666 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:24:58.666 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:24:59.859 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 604 id.app.sbrowser(17697) 48
06-23 19:25:01.678 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:01.678 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:03.861 1166 1166 D io_stats: !@ Write_top(KB): id.app.sbrowser(17697) 48
06-23 19:25:04.695 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:04.695 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:06.521 2103 4069 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface#112049(seamlessTransition:0)
06-23 19:25:06.521 2103 4069 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface#112046(seamlessTransition:0)
06-23 19:25:06.521 2103 4069 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity$_17697#112040(seamlessTransition:0)
06-23 19:25:06.522 2103 2223 D RenderEngine: [SEC_SF_EFFECTS] drawLayersInternal,1483, Rendering layer com.sec.android.app.sbrowser/SbrowserChildSurface#112049 at index 1
06-23 19:25:06.522 2103 2223 D RenderEngine: [SEC_SF_EFFECTS] drawLayersInternal,1483, Rendering layer com.sec.android.app.sbrowser/SbrowserChildSurface#112046 at index 2
06-23 19:25:06.522 2103 2223 D RenderEngine: [SEC_SF_EFFECTS] drawLayersInternal,1483, Rendering layer com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity$_17697#112040 at index 3
06-23 19:25:07.716 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:07.716 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:07.864 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 736 id.app.sbrowser(17697) 80
06-23 19:25:08.369 9600 9766 I PowerManagerService: [PWL] SCREEN_BRIGHT_WAKE_LOCK 'WindowManager/displayId:0' ON_AFTER_RELEASE ACQ=-29s978ms (uid=1000 pid=9600 ws=WorkSource{10329 com.sec.android.app.sbrowser} displayId=0 lock=9b9dc97)
06-23 19:25:10.737 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:10.738 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:13.754 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:13.755 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:13.755 9600 10083 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.bindService:2167 com.samsung.android.server.wifi.SemWifiIntelligentConnectionManager.iwh_predict_action:8 com.samsung.android.server.wifi.SemWifiIntelligentConnectionManager.-$$Nest$miwh_predict_action:1 com.samsung.android.server.wifi.SemWifiIntelligentConnectionManager$IntelligentConnectionManagerHandler.handleMessage:762 android.os.Handler.dispatchMessage:110 
06-23 19:25:13.967 9600 10083 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.stopService:2080 com.samsung.android.server.wifi.SemWifiIntelligentConnectionManager$IntelligentConnectionManagerHandler.handleMessage:247 android.os.Handler.dispatchMessage:110 android.os.Looper.loopOnce:273 android.os.Looper.loop:363 
06-23 19:25:15.868 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 1448 id.app.sbrowser(17697) 96 jbd2/sda9-8(1130) 8
06-23 19:25:16.779 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:16.779 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:19.789 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:19.789 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:22.808 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:22.808 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:23.874 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:0(5739) 952 id.app.sbrowser(17697) 48
06-23 19:25:25.821 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:25.821 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:27.875 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 984 id.app.sbrowser(17697) 48 vendor.samsung.(2036) 8
06-23 19:25:28.839 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:28.840 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:31.856 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:31.856 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:32.856 11830 11830 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.startService:2068 android.content.ContextWrapper.startService:872 android.content.ContextWrapper.startService:872 com.sec.android.diagmonagent.sa.receiver.CFLogReceiver.onReceive:56 android.app.ActivityThread.handleReceiver:5663 
06-23 19:25:32.895 11830 11830 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.startService:2068 android.content.ContextWrapper.startService:872 android.content.ContextWrapper.startService:872 com.sec.android.diagmonagent.sa.receiver.CFLogReceiver.onReceive:56 android.app.ActivityThread.handleReceiver:5663 
06-23 19:25:34.867 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:34.867 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:36.597 2103 4069 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface#112049(seamlessTransition:0)
06-23 19:25:37.887 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:37.887 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:39.882 1166 1166 D io_stats: !@ Write_top(KB): id.app.sbrowser(17697) 68
06-23 19:25:40.905 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:40.906 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:42.899 11830 11830 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.startService:2068 android.content.ContextWrapper.startService:872 android.content.ContextWrapper.startService:872 com.sec.android.diagmonagent.sa.receiver.CFLogReceiver.onReceive:56 android.app.ActivityThread.handleReceiver:5663 
06-23 19:25:42.912 11830 11830 W ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.startService:2068 android.content.ContextWrapper.startService:872 android.content.ContextWrapper.startService:872 com.sec.android.diagmonagent.sa.receiver.CFLogReceiver.onReceive:56 android.app.ActivityThread.handleReceiver:5663 
06-23 19:25:43.924 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:43.924 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:46.937 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:46.937 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:47.887 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 596 id.app.sbrowser(17697) 56
06-23 19:25:49.950 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:49.951 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:51.890 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:0(5739) 540 id.app.sbrowser(17697) 48
06-23 19:25:52.967 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:52.967 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:54.371 9600 12055 D SGM:GameManager: identifyForegroundApp. com.sec.android.app.sbrowser, mCurrentUserId: 0, callerUserId: 0
06-23 19:25:55.894 1166 1166 D io_stats: !@ Write_top(KB): system_server(9600) 56 id.app.sbrowser(17697) 48 .gms.persistent(8716) 44
06-23 19:25:55.993 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:55.993 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:59.012 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:25:59.012 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:25:59.900 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 964 id.app.sbrowser(17697) 48
06-23 19:26:02.030 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:26:02.030 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:26:05.057 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:26:05.057 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:26:06.678 2103 2184 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface#112049(seamlessTransition:0)
06-23 19:26:06.678 2103 2184 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface#112046(seamlessTransition:0)
06-23 19:26:06.678 2103 2184 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity$_17697#112040(seamlessTransition:0)
06-23 19:26:06.680 2103 2223 D RenderEngine: [SEC_SF_EFFECTS] drawLayersInternal,1483, Rendering layer com.sec.android.app.sbrowser/SbrowserChildSurface#112049 at index 1
06-23 19:26:06.680 2103 2223 D RenderEngine: [SEC_SF_EFFECTS] drawLayersInternal,1483, Rendering layer com.sec.android.app.sbrowser/SbrowserChildSurface#112046 at index 2
06-23 19:26:06.680 2103 2223 D RenderEngine: [SEC_SF_EFFECTS] drawLayersInternal,1483, Rendering layer com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity$_17697#112040 at index 3
06-23 19:26:07.906 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 1072 id.app.sbrowser(17697) 68 ung.faceservice(16447) 4
06-23 19:26:08.075 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:26:08.075 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:26:11.088 9600 10083 D SGM:GameManager: identifyGamePackage. com.sec.android.app.sbrowser, mCurrentUserId: 0, callingMethodInfo: com.samsung.android.game.SemGameManager.isGamePackage(SemGameManager.java:106)
06-23 19:26:11.088 9600 10083 D SGM:SemGameManager: isGamePackage(), pkgName=com.sec.android.app.sbrowser, ret=false
06-23 19:26:11.907 1166 1166 D io_stats: !@ Write_top(KB): kworker/u16:2(12924) 764 id.app.sbrowser(17697) 48

The tag SGM stands for Samsung Game Manager (part of Samsung’s Game Optimisation Service ecosystem, commonly linked to com.samsung.android.game.gametools or com.samsung.android.game.gos). The Gaming hub app is a separate package: com.samsung.android.game.gamehome.

The logs reveal three deeply concerning background operations happening simultaneously every few seconds:

SGM is used to profile our activity

Samsung Game Manager is hammering the CPU every 2 to 3 seconds (example: 19:25:37, 19:25:40, 19:25:43) running an interception check (identifyGamePackage).

  • It keeps checking if the open app and in this instance browser window (com.sec.android.app.sbrowser) is a “game package” so it can apply internal performance overrides, GPU clock scaling, and resolution throttling.
  • Even though the function continuously returns ret=false (the expected result as it is just a standard web browser), the loop never backs off. It keeps executing wasting CPU cycles. Why it even needs to be a poorly designed loop is beyond me (and also beyond the point of this post).

This seems fairly harmless right? Lets delve deeper.

SurfaceFlinger is used for screen interception

At 19:25:06.521, 19:25:36.597 and again at: 19:26:06.678, SurfaceFlinger (Android’s underlying hardware display compositor) registers a series of Capture layer lists: commands:textI SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface…
D RenderEngine: [SEC_SF_EFFECTS] drawLayersInternal… Rendering layer…

  • The system’s graphics renderer is actively duplicating, rendering, and rendering-to-buffer the literal visual layers of the active browser screen (SBrowserMainActivity).
  • Likely part of the issue causing audio/video de-sync.
  • Here’s the scary part, right after these screen captures execute, look at the very next line (19:26:07.906): ung.faceservice (Samsung Face Service, com.samsung.android.smartface) spikes in disk-write activity (io_stats). The system is taking the captured screen layouts and passing them to background analysis services.

Lets look a little deeper

The display compositor breaks the browser window into three distinct memory targets simultaneously:

06-23 19:25:06.521 2103 4069 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface#112049(seamlessTransition:0)
06-23 19:25:06.521 2103 4069 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/SbrowserChildSurface#112046(seamlessTransition:0)
06-23 19:25:06.521 2103 4069 I SurfaceFlinger: Capture layer list: com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity$_17697#112040(seamlessTransition:0)

Normally a video player establishes a single consumer surface point. The SurfaceFlinger splits the render tree into two distinct SbrowserChildSurface buffers (#112131 and #112130) running alongside the main thread Samsung Browser.

  • One surface layer maps out the player UI which is what we see.
  • The second subsurface copy is a dedicated frame-grabbing capture mirror which is duplicating media data blocks in real time so background analysis layers can hook the video stream frame by frame.

I suspect that this is the cause behind the micro-stuttering and the spikes in power draw are directly tied to the render thread which appears to freeze during frame processing until the transaction finishes.

At this point I revised the command I was using to parse Logcat and decided to include more Samsung related keywords for extraction.

Re-running a video in the Samsung Browser here’s another interesting log extraction:

06-23 21:22:55.688 I/ImeTracker( 9600): com.sec.android.app.sbrowser:fc4a258c: onRequestHide at ORIGIN_SERVER reason HIDE_UNSPECIFIED_WINDOW fromUser false
06-23 21:22:55.690 I/HoneySpace.LauncherProvider(10959): call - com.sec.android.app.sbrowser, get_hotseat_item_count, null
06-23 21:22:55.691 I/HoneySpace.LauncherProvider(10959): call - com.sec.android.app.sbrowser, get_hotseat_item, null
06-23 21:22:55.692 I/HoneySpace.LauncherProvider(10959): call - com.sec.android.app.sbrowser, get_hotseat_item, null
06-23 21:22:55.693 D/InsetsSourceProvider( 9600): updateControlForTarget: control=InsetsSourceControl: {3 mType=ime mSurfacePosition=Point(0, 84) mInsetsHint=Insets{left=0, top=0, right=0, bottom=929}}, target=Window{b74e1de u0 com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity}, from=com.android.server.wm.ImeInsetsSourceProvider.updateControlForTarget:17 com.android.server.wm.InsetsStateController.onControlTargetChanged:83 com.android.server.wm.DisplayContent.updateImeControlTarget:21 com.android.server.wm.DisplayContent.updateImeInputAndControlTarget:156 com.android.server.wm.WindowManagerService$LocalService.updateInputMethodTargetWindow:64 
06-23 21:22:55.694 D/SurfaceComposerClient( 9600): setCornerRadius ## b74e1de com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity#112306 cornerRadius=0.000000
06-23 21:22:55.702 I/PAT ( 3025): CallerChecker: forceCheckCallingPackage com.sec.android.app.sbrowser
06-23 21:22:55.708 I/BLASTBufferQueue_Java( 1447): update, w= 1080 h= 2340 mName = VRI[SBrowserMainActivity]@c2adc78 mNativeObject= [MEM_PTR] sc.mNativeObject= 0xb400007d081e9f50 format= -3 caller= android.view.ViewRootImpl.updateBlastSurfaceIfNeeded:3574 android.view.ViewRootImpl.relayoutWindow:11685 android.view.ViewRootImpl.performTraversals:4804 android.view.ViewRootImpl.doTraversal:3924 android.view.ViewRootImpl$TraversalRunnable.run:12903 android.view.Choreographer$CallbackRecord.run:1901 
06-23 21:22:55.708 I/WindowManager( 9600): Relayout Window{b74e1de u0 com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity}: viewVisibility=0 req=1080x2340 ty=1 d0
06-23 21:22:55.708 I/VRI[SBrowserMainActivity]@c2adc78( 1447): Relayout returned: old=(0,0,1080,2340) new=(0,0,1080,2340) relayoutAsync=true req=(1080,2340)0 dur=0 res=0x0 s={true 0xb400007e4821af10} ch=false seqId=0
06-23 21:22:55.708 D/SurfaceComposerClient( 9600): setCornerRadius ## b74e1de com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity#112306 cornerRadius=0.000000
06-23 21:22:55.709 D/WindowManager( 9600): updateSystemBarAttributes: displayId=0, focusedCanBeNavColorWin=false, win=Window{b74e1de u0 com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity}, navColorWin=Window{b74e1de u0 com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity}, caller=com.android.server.wm.DisplayPolicy.finishPostLayoutPolicyLw:17 com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction$1:195 com.android.server.wm.RootWindowContainer.performSurfacePlacementNoTrace:59 
06-23 21:22:55.709 D/SurfaceComposerClient( 9600): setCornerRadius ## b74e1de com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity#112306 cornerRadius=0.000000
06-23 21:22:55.710 D/NavigationBar(10397): onSystemBarAttributesChanged() - displayId:0, appearance:0, packageName: com.sec.android.app.sbrowser, navbarColorManagedByIme:false
06-23 21:22:55.710 I/SurfaceFlinger( 2103): id=112312 createSurf, flag=20004, Bounds for - com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity@0#112312
06-23 21:22:55.710 I/SurfaceFlinger( 2103): id=112313 createSurf, flag=84004, 19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0#112313
06-23 21:22:55.710 I/SurfaceFlinger( 2103): id=112314 createSurf, flag=44000, 19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0(BLAST)#112314
06-23 21:22:55.711 I/SurfaceFlinger( 2103): id=112315 createSurf, flag=20404, Background for 19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0#112315
06-23 21:22:55.713 I/BLASTBufferQueue_Java( 1447): new BLASTBufferQueue, mName= 19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0 mNativeObject= 0xb400007e382ea010 caller= android.view.SurfaceView.createBlastSurfaceControls:1781 android.view.SurfaceView.updateSurface:1450 android.view.SurfaceView.lambda$new$0:280 android.view.SurfaceView.$r8$lambda$NfZyM_TG8F8lqzaOVZ7noREFjzU:0 android.view.SurfaceView$$ExternalSyntheticLambda1.onPreDraw:0 android.view.ViewTreeObserver.dispatchOnPreDraw:1229 android.view.ViewRootImpl.performTraversals:5448 android.view.ViewRootImpl.doTraversal:3924 android.view.ViewRootImpl$TraversalRunnable.run:12903 android.view.Choreographer$CallbackRecord.run:1901 
06-23 21:22:55.713 I/BLASTBufferQueue_Java( 1447): update, w= 1080 h= 2340 mName = 19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0 mNativeObject= 0xb400007e382ea010 sc.mNativeObject= 0xb400007d081ef590 format= -3 caller= android.view.SurfaceView.createBlastSurfaceControls:1782 android.view.SurfaceView.updateSurface:1450 android.view.SurfaceView.lambda$new$0:280 android.view.SurfaceView.$r8$lambda$NfZyM_TG8F8lqzaOVZ7noREFjzU:0 android.view.SurfaceView$$ExternalSyntheticLambda1.onPreDraw:0 android.view.ViewTreeObserver.dispatchOnPreDraw:1229 
06-23 21:22:55.713 I/SV[27248603 SBrowserMainActivity]( 1447): pST: sr = Rect(0, 0 - 1080, 2340) sw = 1080 sh = 2340
06-23 21:22:55.713 I/SV[27248603 SBrowserMainActivity]( 1447): updateSurface: mVisible = true mSurface.isValid() = true
06-23 21:22:55.713 I/SV[27248603 SBrowserMainActivity]( 1447): updateSurface: mSurfaceCreated = false surfaceChanged = true visibleChanged = true
06-23 21:22:55.713 I/SV[27248603 SBrowserMainActivity]( 1447): surfaceCreated 1 #8 android.view.SurfaceView{19fc7db V.E...... ......ID 0,0-1080,2340}
06-23 21:22:55.713 I/SV[27248603 SBrowserMainActivity]( 1447): surfaceChanged (1080,2340) 1 #8 android.view.SurfaceView{19fc7db V.E...... ......ID 0,0-1080,2340}
06-23 21:22:55.714 I/VRI[SBrowserMainActivity]@c2adc78( 1447): registerCallbackForPendingTransactions
06-23 21:22:55.714 I/SV[27248603 SBrowserMainActivity]( 1447): uSP: rtp = Rect(0, 0 - 1080, 2340) rtsw = 1080 rtsh = 2340
06-23 21:22:55.715 I/SV[27248603 SBrowserMainActivity]( 1447): onSSPAndSRT: pl = 0 pt = 0 sx = 1.0 sy = 1.0
06-23 21:22:55.715 I/SV[27248603 SBrowserMainActivity]( 1447): aOrMT: VRI[SBrowserMainActivity]@c2adc78 t = android.view.SurfaceControl$Transaction@172d705 fN = 3 android.view.SurfaceView.-$$Nest$mapplyOrMergeTransaction:0 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1932 android.graphics.RenderNode$CompositePositionUpdateListener.positionChanged:401 
06-23 21:22:55.715 I/VRI[SBrowserMainActivity]@c2adc78( 1447): mWNT: t=[MEM_PTR] mBlastBufferQueue=[MEM_PTR] fn= 3 HdrRenderState mRenderHdrSdrRatio=1.0 caller= android.view.SurfaceView.applyOrMergeTransaction:1863 android.view.SurfaceView.-$$Nest$mapplyOrMergeTransaction:0 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1932 
06-23 21:22:55.715 I/VRI[SBrowserMainActivity]@c2adc78( 1447): mWNT: t=0xb400007ce8273150 mBlastBufferQueue=[MEM_PTR] fn= 3 HdrRenderState mRenderHdrSdrRatio=1.0 caller= android.view.ViewRootImpl$10.onFrameDraw:6536 android.view.ViewRootImpl$4.onFrameDraw:2489 android.view.ThreadedRenderer$1.onFrameDraw:718 
06-23 21:22:55.715 I/SurfaceFlinger( 2103): [LayerHierarchy{RequestedLayerState{ImeContainer#89213 parentId=112296 relativeParentId=112306 z=1} 1 children}] reparent to LayerHierarchy{RequestedLayerState{ActivityRecord{100643615 u0 com.sec.android.app.sbrowser/.SBrowserMainActivity t11363}#112296 parentId=112295} 3 children}

The additional details reveal that SurfaceFlinger is infact creating 4 rendering layers starting at: 06-23 21:22:55.710:

  • Instead of the a standard single-surface video output, the rendering layer splits the buffer tree. It builds a primary SurfaceView, a secondary BLAST (Buffer Layer ASynchronous Transaction) layer, and an independent background surface layer.
  • At 715 (ms) mark the system compositor took the ImeContainer (the protected system layer that handles keyboard, clipboard entries, keystroke caches, and text inputs) and physically stitched it into the internal layer hierarchy of the browser window.

The result is that the reparent command against the ImeContainer is explicitly bound into the browser’s activity hierarchy and with it the system server maintains an active pipe to intercept anything typed, copied, or displayed within that specific browser window frame. Dodgy right? Well there’s more.

A few seconds later the logs show:

06-23 21:22:55.726 I/SamsungAccount(13122): [AIDLInterfaceBinder] [InAIDL] registerCallback start. Package = app.sbrowser.
06-23 21:22:55.726 I/SamsungAccount(13122): [CallbackManager] [InAIDL-CallbackManager] registerCallback success. Package = app.sbrowser.
06-23 21:22:55.726 I/SamsungAccount(13122): [AIDLInterfaceBinder] [InAIDL] registerCallback end. registrationCode : [REDACTED]. Package = app.sbrowser.
06-23 21:22:55.726 I/SamsungAccount(13122): [AccountManagerProvider] Calling package : app.sbrowser.
06-23 21:22:55.727 I/SamsungAccount(13122): [SignatureInfoDbHelper] searchOnUser(fromDb) - [REDACTED][app.sbrowser.][REDACTED] => matched
06-23 21:22:55.728 I/SamsungAccount(13122): [AIDLInterfaceBinder] [InAIDL] requestAccessToken { additional:cc,access_token,api_server_url,user_id,} Package = app.sbrowser.
06-23 21:22:55.731 I/SamsungAccount(13122): [SignatureInfoDbHelper] searchOnUser(fromDb) - [REDACTED][app.sbrowser.][REDACTED] => matched
06-23 21:22:55.731 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] runProcess start. Package = app.sbrowser.
06-23 21:22:55.732 I/SurfaceFlinger( 2103): RequestedLayer [19fc7db SurfaceView[com.sec.android.[...]owser.SBrowserMainActivity]@0#112313] hidden!! flag from(1) --> to(0)
06-23 21:22:55.732 I/SurfaceFlinger( 2103): RequestedLayer [Bounds for - com.sec.android.app.sbr[...]rowser.SBrowserMainActivity@0#112312] hidden!! flag from(1) --> to(0)
06-23 21:22:55.732 I/SurfaceFlinger( 2103): [LayerHierarchy{RequestedLayerState{Background for 19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0#112315 parentId=112313 relativeParentId=112307 z=-2147483648} no children}] RelativeParent to LayerHierarchy{RequestedLayerState{com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity$_1447#112307 parentId=112306} 2 children}
06-23 21:22:55.732 I/SurfaceFlinger( 2103): [LayerHierarchy{RequestedLayerState{19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0#112313 parentId=112312 relativeParentId=112307 z=-1} 2 children}] RelativeParent to LayerHierarchy{RequestedLayerState{com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity$_1447#112307 parentId=112306} 3 children}
06-23 21:22:55.734 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] isCheckBasicProfile = true, needToCheckServer = false. Package = app.sbrowser.
06-23 21:22:55.734 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] isAccessTokenReusable. Package = app.sbrowser.
06-23 21:22:55.734 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] checkAndSetAccessToken. scope is null or empty. Package = app.sbrowser.
06-23 21:22:55.735 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] expiredAccessToken is empty. Package = app.sbrowser.
06-23 21:22:55.735 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] curTimeSec = 1782246175, TimeGap = 8003. Package = app.sbrowser.
06-23 21:22:55.735 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] expiredAccessToken is different from cached token. Package = app.sbrowser.
06-23 21:22:55.735 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] isAccessTokenReusable : true. Package = app.sbrowser.
06-23 21:22:55.737 I/SurfaceFlinger( 2103): id=112316 createSurf, flag=44000, com.sec.android.app.sbrowser/SbrowserNativeWindowSurface#112316
06-23 21:22:55.749 I/SurfaceFlinger( 2103): [com.sec.android.app.sbrowser/SbrowserNativeWindowSurface#112316] attach to parent LayerHierarchy{RequestedLayerState{19fc7db SurfaceView[com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity]@0(BLAST)#112314 parentId=112313} 1 children}
06-23 21:22:55.755 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] AccessToken reuse. runProcess end. Package = app.sbrowser.
06-23 21:22:55.755 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] onProcessFinished. Package = app.sbrowser.
06-23 21:22:55.756 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] checkAccessTokenAndRefreshToken. Package = app.sbrowser.
06-23 21:22:55.756 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] handleProcessSuccessResult start. Package = app.sbrowser.
06-23 21:22:55.756 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] setAdditionalInfo start. [cc, access_token, api_server_url, user_id] Package = app.sbrowser.
06-23 21:22:55.756 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] Unhandled key : access_token Package = app.sbrowser.
06-23 21:22:55.756 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] setAdditionalInfo finish. Package = app.sbrowser.
06-23 21:22:55.761 I/SamsungAccount(13122): [AIDLInterfaceBinder] [InAIDL] requestRequiredConsent { ac_to_:? common_c_i:? language:? region:? ap_re_:?} Package = app.sbrowser.
06-23 21:22:55.761 I/SamsungAccount(13122): [AccessTokenRunnable] [InAIDL-AccessTokenRunnable] handleProcessSuccessResult finish. Package = app.sbrowser.
06-23 21:22:55.764 I/SamsungAccount(13122): [SignatureInfoDbHelper] searchOnUser(fromDb) - [REDACTED][app.sbrowser.][REDACTED] => matched
06-23 21:22:55.764 I/SamsungAccount(13122): [RequiredConsentRunnable] [InAIDL-RequiredConsentRunnable] isValidAppAccessToken Package = app.sbrowser.
06-23 21:22:55.764 I/SamsungAccount(13122): [RequiredConsentRunnable] [InAIDL-RequiredConsentRunnable] accessToken is matched to cache data Package = app.sbrowser.

Here we see the SamsungAccount package queried for a user identity profile, requesting the cloud server URL (api_server_url), a unique encrypted user_id, and a high-level access_token at 06-23 21:22:55.761 we also see a query for regional rules assigned to a specific identity profile.

The system passes parameters tracking information including: language profile, my exact geographical region, and my account compliance check status (requestRequiredConsent). This appears to be one of the mechanism used to verify if a specific user account profile falls under restrictive regional policies (for example these could be specific European, UK, or corporate network filters).

Samsung Face Service

At first a user may assume that this relates to the functionality where the device can keep the screen turned on whilst you are looking at it; useful in scenarios where you’re reading and not interacting with the devices. Videos (media playback) on the other hand do not need or typically use that functionality. If you are watching a movie or a continuous video stream, the media player itself calls a standard Android API component called a WakeLock (specifically SCREEN_BRIGHT_WAKE_LOCK which you can also see in the logcat trace at 19:25:08.369).

What is com.samsung.faceservice actually doing in that case? The fact that com.samsung.faceservice (or its sister components under com.samsung.android.smartface) actively fires and writes data to disk (io_stats) during video playback proves it is executing a completely separate task.

This background task uses SurfaceFlinger display server capturing screen layers (Capture layer list) every 30 seconds. In essence the operating system grabs a snapshot of what is on the display and checks it against the face tracking telemetry logs to correlate what I am are looking at, with how I am physically responding to it.

This too likely explains the heavy battery drain and the sudden video stuttering; but now as well as being alarmed I’m even more curious on what is going on.

Additional details

Whilst tracing this through logcat I also managed to capture a crash partially because at this stage I had already started removing permissions for some of these background services; this crash however adds further details:

06-23 21:23:28.415 D/io_stats( 1166): !@ Write_top(KB): kworker/u16:4(31793) 964 f2fs_ckpt-254:6(5102) 384 id.app.sbrowser(2283) 128
06-23 21:23:28.536 D/CoreBackPreview( 9600): startBackNavigation currentTask=Task{1d3c8ca #11365 type=standard A=10329:com.sec.android.app.sbrowser}, topRunningActivity=ActivityRecord{72436789 u0 com.sec.android.app.sbrowser/.SBrowserMainActivity t11365}, callbackInfo=OnBackInvokedCallbackInfo{mCallback=android.window.IOnBackInvokedCallback$Stub$Proxy@ac583f7, mPriority=0, mIsAnimationCallback=false, mOverrideBehavior=0}, currentFocus=Window{5f9cb07 u0 com.sec.android.app.sbrowser/com.sec.android.app.sbrowser.SBrowserMainActivity}
06-23 21:23:28.743 I/si__SBrowserMainActivity( 2283): onBackPressed
06-23 21:23:28.746 I/dslte[9.0.2]@TextExtractionImpl( 2283): TextExtraction initialized at com.sec.android.app.sbrowser
06-23 21:23:28.746 I/Recognizer( 2283): SEC_FLOATING_FEATURE_CAMERA_CONFIG_STRIDE_OCR_VERSION=[V2]
06-23 21:23:28.746 I/dslte[9.0.2]@TextExtractionImpl( 2283): isSupported OCR_ALL:true
06-23 21:23:28.783 E/id.app.sbrowser( 2283): ----- class 'Lcom/samsung/android/vexfwk/bitmap/VexFwkBitmap;' cl=0x201a9e8 -----
06-23 21:23:28.783 E/id.app.sbrowser( 2283):   objectSize=212 (208 from super)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):   access=0x0000.0011
06-23 21:23:28.783 E/id.app.sbrowser( 2283):   super='java.lang.Class<java.lang.Object>' (cl=0x0)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):   vtable (0 entries, 11 in super):
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      0: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.<clinit>()
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      1: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.<init>()
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      2: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.access$copyBitmapToBitmapNative(android.graphics.Bitmap, android.graphics.Bitmap, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      3: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.access$copyBitmapToIntArrayNative(android.graphics.Bitmap, int[], int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      4: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.access$copyByteArrayToBitmapNative(byte[], android.graphics.Bitmap, int, int, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      5: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.access$copyIntArrayToBitmapNative2(int[], android.graphics.Bitmap, int, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      6: android.graphics.Bitmap com.samsung.android.vexfwk.bitmap.VexFwkBitmap.convertToBitmap(byte[], android.util.Size, int, int, android.graphics.Bitmap$Config)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      7: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(android.graphics.Bitmap, android.graphics.Bitmap)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      8: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(android.graphics.Bitmap, android.graphics.Bitmap, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      9: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(android.graphics.Bitmap, android.graphics.Bitmap, android.graphics.Rect)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     10: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(android.graphics.Bitmap, int[])
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     11: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(android.graphics.Bitmap, int[], int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     12: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(android.graphics.Bitmap, int[], android.graphics.Rect)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     13: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(int[], android.graphics.Bitmap)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     14: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(int[], android.graphics.Bitmap, int, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     15: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmap(int[], android.graphics.Bitmap, android.graphics.Rect, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     16: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmapToBitmapNative(android.graphics.Bitmap, android.graphics.Bitmap, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     17: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyBitmapToIntArrayNative(android.graphics.Bitmap, int[], int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     18: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyByteArrayToBitmapNative(byte[], android.graphics.Bitmap, int, int, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     19: void com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyIntArrayToBitmapNative2(int[], android.graphics.Bitmap, int, int, int, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):     20: android.graphics.Bitmap com.samsung.android.vexfwk.bitmap.VexFwkBitmap.resizeBitmap(android.graphics.Bitmap, int, int)
06-23 21:23:28.783 E/id.app.sbrowser( 2283):   fields (1 entries):
06-23 21:23:28.783 E/id.app.sbrowser( 2283):      0: static com.samsung.android.vexfwk.bitmap.VexFwkBitmap$Companion com.samsung.android.vexfwk.bitmap.VexFwkBitmap.Companion
06-23 21:23:28.784 E/id.app.sbrowser( 2283): Failed to register native method com.samsung.android.vexfwk.bitmap.VexFwkBitmap.copyIntArrayToBitmapNative([ILandroid/graphics/Bitmap;IIII)V in /data/app/~~wnh1Sqm0qkoT-7SEQMGh4Q==/com.sec.android.app.sbrowser-up7RideyAVUbe0AE3DSPRA==/base.apk!classes2.dex
06-23 21:23:28.808 I/si__SBrowserTab( 2283): goBack
06-23 21:23:28.836 I/ActivityManager( 9600): Start proc 2742:com.sec.android.app.sbrowser:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:3/u0i79 for service {com.sec.android.app.sbrowser/org.chromium.content.app.SandboxedProcessService0:3}
06-23 21:23:28.861 I/SamsungAccount(13122): [AccountManagerProvider] Calling package : app.sbrowser.

Upon navigating away from the activity with the back button the browser intercepted the action and triggered: TextExtractionImpl which is Samsung’s on-device optical character recognition (OCR) service it then called: Samsung’s underlying system-level hardware profile driver (SEC_FLOATING_FEATURE_CAMERA_CONFIG_STRIDE_OCR_VERSION=[V2]). This queries the chip to verify if it can run OCR_ALL.

It then allocated memory to call: VexFwkBitmap from VexFwk which is Samsung’s Visual Expression Framework (com.samsung.android.vexfwk.service). The crash reveals 3 interesting methods:

  • access$copyBitmapToBitmapNative
  • access$copyBitmapToIntArrayNative
  • access$copyByteArrayToBitmapNative

These methods appear to exist for the purpose of bypassing standard app-sandbox boundaries; grab the raw uncompressed byte arrays from the active display frames or decoding video containers, and force copy them into integer arrays (int[]) and native system bitmap memory buffers (android.graphics.Bitmap) for analysis.

The last log entry shows it instantly executed a background call back to the Samsung Account token manager. It did this to verify my identity profile state and prepare an error telemetry packet linked to my cloud user configuration.

Conclusion

What I discovered here is a system operating with an astonishingly deep level of interconnected, real-time tracking.

The implementation reveals a trade-off: the pursuit of a “seamless” experience is achieved through deep, persistent monitoring. The system is not just running for us; it is constantly analysing, duplicating, and logging our visual input, security context, typed input and what we consume.

It forces a critical question; How much of my personal experience is being traded for this level of granular, continuous data collection? I’m not sure where this goes, but for now, I will say this: “F*ck you Samsung!”.

Where do we go from here?

You could do what I’ve done and disable and restrict the permissions on many of the packages mentioned here; I’ve included a script to achieve this below or separately the ADB commands to achieve this.

Packages identified from this debugging session

PackageADB commands
Samsung Smart Faceadb shell am force-stop com.samsung.android.smartface
adb shell am force-stop com.samsung.android.smartface.overlay
adb shell cmd appops set com.samsung.android.smartface RUN_IN_BACKGROUND ignore
adb shell cmd appops set com.samsung.android.smartface START_FOREGROUND ignore
adb shell cmd appops set com.samsung.android.smartface.overlay RUN_IN_BACKGROUND ignore
adb shell pm uninstall -k --user 0 com.samsung.android.smartface
adb shell pm uninstall -k --user 0 com.samsung.android.smartface.overlay
Samsung Diagnostic Monitoring Agentadb shell am force-stop com.sec.android.diagmonagent
adb shell cmd appops set com.sec.android.diagmonagent RUN_IN_BACKGROUND ignore
adb shell pm uninstall -k --user 0 com.sec.android.diagmonagent
Samsung Game Toolsadb shell am force-stop com.samsung.android.game.gametools
adb shell cmd appops set com.samsung.android.game.gametools RUN_IN_BACKGROUND ignore
adb shell pm uninstall -k --user 0 com.samsung.android.game.gametools
Samsung Wi-Fi Tips
Samsung’s Intelligent Wi-Fi
adb shell am force-stop com.samsung.android.wifi.intelligence
adb shell am force-stop com.samsung.android.net.wifi.wifiguider
adb shell cmd appops set com.samsung.android.wifi.intelligence RUN_IN_BACKGROUND ignore
adb shell cmd appops set com.samsung.android.net.wifi.wifiguider RUN_IN_BACKGROUND ignore
adb shell pm uninstall -k --user 0 com.samsung.android.wifi.intelligence
adb shell pm uninstall -k --user 0 com.samsung.android.net.wifi.wifiguider
Samsung OCR Serviceadb shell am force-stop com.samsung.android.sdk.ocr
adb shell cmd appops set com.samsung.android.sdk.ocr RUN_IN_BACKGROUND ignore
adb shell pm uninstall -k --user 0 com.samsung.android.sdk.ocr
Samsung Browseradb shell pm uninstall com.sec.android.app.sbrowser

Removal with a script (Bash)

Here is a Bash script that covers more packages; it supports removal and restoration, ensure that you had ADB installed and you are connected to a device then run with:

  • Removal: bash package_control.sh or bash package_control.sh remove
  • Restoration: bash package_control.sh restore
#!/bin/bash


declare -a samsung_packages=(
	# Core packages identified in debug
	"com.samsung.android.smartface"
	"com.samsung.android.smartface.overlay"
	"com.sec.android.diagmonagent"
	"com.samsung.android.game.gametools"
	"com.samsung.android.game.gos"
	"com.samsung.android.wifi.intelligence"
	"com.samsung.android.net.wifi.wifiguider"
	"com.samsung.android.sdk.ocr"
	"com.samsung.android.vexfwk.service"
	# Other AI related packages
	"com.samsung.android.intelligence.service"
	"com.samsung.android.visionintelligence"
	"com.samsung.android.intellivoiceservice"
	"com.samsung.android.vision.model"
	"com.samsung.android.visual.cloudcore"
	"com.samsung.android.aicore"
	"com.samsung.android.intellivoiceservice"
	"com.samsung.android.bixby.agent"
	"com.samsung.android.bixby.service"
	"com.samsung.android.bixbyvision.framework"
	"com.rsupport.rs.activity.rsupport.aas2"
	"com.samsung.android.app.tips"
	"com.samsung.android.inputshare"
)

declare -a foreground_start_packages=(
	"com.samsung.android.smartface"
)

declare -a google_packages=(
	"com.google.android.as"
	"com.google.android.as.oss"
	"com.google.internal.tangram.safetycore"
	"com.google.android.apps.bard"
)

# Other packages for standard uninstallation
declare -a other_packages=(
	"com.sec.android.app.sbrowser"
	"com.samsung.android.inputshare"
	"com.samsung.android.voc"
	"com.samsung.android.game.gamehome"
)

# Disables and remove packages from the `user 0`.
disable_packages() {
	local packages
	packages=$(adb shell pm list packages 2>/dev/null | tr -d '\r' | sed 's/package://g')
    
    # Determine if the ADB connection is available
    if [[ -z "$packages" ]]; then
        echo "Error: No device detected or ADB connection failed."
        return 1
    fi

	for i in "$@"
	do
		echo "Disabling package: $i"
		adb shell am force-stop "$i" >/dev/null 2>&1
		adb shell cmd appops set "$i" RUN_IN_BACKGROUND ignore >/dev/null 2>&1
		adb shell cmd appops set "$i" START_FOREGROUND ignore >/dev/null 2>&1

		local adb_output
        adb_output=$(adb shell pm uninstall --user 0 "$i" 2>&1)
        echo " -> ADB Output: $adb_output"
	done
}

# Restores packages for user annd reapplies permissions. 
restore_packages() {
	local packages

	for i in "$@"
	do
		echo "Restoring package: $i"
		local adb_output
        adb_output=$(adb shell cmd package install-existing --user 0 "$i" 2>&1)
        echo " -> ADB Output: $adb_output"
		adb shell cmd appops set "$i" RUN_IN_BACKGROUND allow >/dev/null 2>&1

		if contains_element "$i"; then
			adb shell cmd appops set "$i" START_FOREGROUND allow >/dev/null 2>&1
		fi
	done
}

# Checks if package name is within the foreground package list
# Re-grant foreground permission
foreground_check() {
	local search="$1"

	for i in "$@"; do
	    [[ "$i" == "$search" ]] && return 0
	done
	return 1
}

# Standard uninstallation
uninstall_packages() {
	local packages

	for i in "$@"
	do
		echo "Removing package: $i"
		local adb_output
        adb_output=$(adb shell pm uninstall "$i" 2>&1)
        echo " -> ADB Output: $adb_output"
	done
}

# Toggle between REMOVE/RESTORE operations; defaults to remove
ACTION="${1:-remove}"
case "$ACTION" in
    "remove")
        echo "Executing: REMOVE mode"
        disable_packages "${samsung_packages[@]}"
		disable_packages "${google_packages[@]}"
		uninstall_packages "${other_packages[@]}"
        ;;
        
    "restore")
        echo "Executing: RESTORE mode"
        restore_packages "${samsung_packages[@]}"
        restore_packages "${google_packages[@]}"
        ;;
        
    *)
        # Handle invalid inputs gracefully
        echo "Error: Unknown option '$ACTION'"
        echo "Usage: $0 [remove|restore] (Defaults to remove)"
        exit 1
        ;;
esac
package_control.shView rawView file on GitLab

These aren’t the only packages I would suggest removing; I’ll follow this post up with another more detailed article on what I suggest crippling and disabling.

But ultimately changing to different brand and device is likely the better solution, one that supports either GrapheneOS (generally limited to Pixel devices) or Lineage OS depending on your needs. Note moving to a GrapheneOS or Lineage OS comes with it’s own trade offs; you’ll loose access to the Play Store and apps that rely on Play Store functionality will have limited or no functionality, apps that stand out here include access to many banking apps1 that check the integrity of your devices (mainly via Google Play Store checks).

1 As an alternative you could login to banking services through the browser where supported, if you’re using a banking service doesn’t have a website consider changing your bank. An unfortunate battle between trade-offs, do you sacrifice your privacy for convenient functionality?

Leave a Reply

I'm pleased you have chosen to leave a comment and engage in a meaningful conversation. Please keep in mind that comments are moderated according to our privacy policy, links are set to nofollow.

Your email address will not be published. Required fields are marked *