CLOSE
Android Sandboxing - How Android Keeps Apps Isolated

Android Sandboxing - How Android Keeps Apps Isolated

Updated on 20 Oct, 2026 30 mins read 50 views

Android sandboxing is a security mechanism that prevents one app from freely accessing another app's private data or interfering with its execution.

For example, suppose you install WhatsApp, Instagram, and a banking app on your phone. All three apps run on the same Android operating system, use the same hardware, and may communicate with system services.

Yet Instagram should not be able to open WhatsApp's private message database, and WhatsApp should not be able to read your banking app's private files.

Android's application sandbox provides the underlying isolation that makes this possible. It is enforced primarily through Linux-level security mechanisms, with additional protections from SELinux and Android's permission system.

What does a sandbox mean?

Imagine three people working in separate locked rooms inside one building.

Room A: WhatsApp
Room B: Instagram
Room C: Banking App

All three rooms are inside the same building, just as all three apps runs on the same phone.

The rooms represent security boundaries, not separate physical phones.

Android allows apps to use shared resources through controlled mechanisms, but an app doesn't automatically get access to another app's private data just because both apps are installed on the same device.

How does Android actually implement sandboxing?

The key is that Android does not rely on just one security feature.

Multiple mechanisms work together.

1 Linux UID – each app gets its own operating-system identity

This is one of the most fundamental parts of of the Android sandbox.

UID stands for User Identifier. Linux uses it to identify the user under which a process runs.

When Android installs an application, it assigns the app a Linux identity for a given Android user or profile. Apps that aren't explicitly permitted to share an identity run under separate app identities.

For example, imagine these illustrative UIDs:

ApplicationExample UID
WhatsApp10241
Instagram10272
Banking App10305

These numbers are examples, not actual UIDs from the phone.

When WhatsApp runs, its process operates under its assigned identity. Instagram uses its own identity.

Linux checks that identity when the process attempts to access files protocted by ordinary file ownership and permissions.

2 File permissions – private files belong to the app

An Android app commonly stores private files in a location like:

/data/user/0/com.example.app/
├── files/
├── cache/
├── databases/
└── shared_prefs/

Conceptually, the directory is owned and protected so the app can access its private data while unrelated apps cannot access it through ordinary filesystem operations. Android's security guidance recommends using internal app storage for private data.

Imagine the directory has restrictive permissions similar to 0700, meaning only the owner can read, write, and traverse it.

App A's UID  → can access App A's private files
App B's UID  → cannot normally access App A's private files

The kernel enforces the applicable file permissions. A normal app cannot simply claim to be another app's UID.

3 SELinux – another layer of access control

Linux UIDs and file operations are not the whole story.

Android also uses SELinux, which stands for Security-Enhanced Linux.

SELinux applies mandatory access control (MAC). It uses security policies to define which processes can acces which resources.

Android's SELinux policies follow a default-deny approach: operations not explicitly allowed by the applicable policy are denied.

Think about the difference this way:

  • UID and file permissions: Does this process's identity have ordinary permission to access this file?
  • SELinux: Does the applicable security policy allow this process to perform this action on this resource?

Both checks can matter.

4 Restricted system calls

Apps ultimately uses Linux system calls to perform operations such as opening files, creating processes and communicating with the operating system.

Android adds further protection through mechanisms such as seccomp-BPF, which can restrict the system calls available to application processes. This reduces the kernel attack surface exposed to an app.

UID and GID

UID identifies which user a process runs as. GID identifies the group or groups that process belongs to. Android uses these Linux concepts to control which files, directories, and other resources a process can access.

The problem UID and GID solve

Imagine your Samsung phone has three apps:

  • Chrome
  • Proton Mail
  • A banking app

Each app stores private data. If every app ran under the same operating-system identity, it would be much harder to isolate their files from one another.

Linux solves this problem using user and group identities.

Chrome: UID: 10241, GID membership: illustrative
Proton Main: UID: 10272, GID membership: illustrative
Banking app: UID: 10305, GID membership: illustrative

Because these apps normally run under separate Linux UIDs, one app cannot simply access another app's private files. Linux checks the caller's identity against the applicable access-control rules.

What exactly is a UID?

UID stands for User Identifier.

Linux assigns each running process a user identity. The identity represented internally by a number.

For example:

UID 0 -> root (superuser)
UID 1000 -> commonly system on Android
UID 2000 -> commonly shell on Android
UID 10241 -> illustrative application UID

The key idea is that the kernel checks the process's UID when enforcing many access-control rules.

Try it on your phone:

From your Windows terminal, run:

adb shell id
C:\>adb shell id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid) context=u:r:shell:s0

This tells us the command is executing under the shell user identity rather than automatically running as root.

Now run:

adb shell

Then:

su
id

Output:

C:\>adb shell
greatlte:/ $ su
greatlte:/ # id
uid=0(root) gid=0(root) groups=0(root) context=u:r:eftsu:s0
greatlte:/ #

If su successfully switches to root, you should see a UID of 0.

What exactly is a GID?

GID stands for Group Identifier.

Linux groups allows multiple users or processes to receive shares access to particular resources without giving them all the same UID.

For example, imagine a file with these ownership and permission details:

-rw-r-----  alice  developers  report.txt

Conceptually, this means:

  • The owner, alice, can read and write.
  • Members of the developers group can read.
  • Other users have no access through these permission bits.

Android uses the same general Linux ownership and permission model, although actual Android identities and policies are more complex.

Important: A GID is not an app's package ID. The package name, UID and GID are different concepts.

How UID and GUID protect /data/data

/data/data/
├── com.android.chrome/
├── ch.protonmail.android/
├── com.Dominos/
└── ...

Conceptually, Android protects each app's private directory using ownership, filesystem permissions and additional security policies.

Suppose two applications have these illustrative identities:

Chrome process
    UID = 10241
         |
         v
/data/data/com.android.chrome/

Proton Mail process
    UID = 10272
         |
         v
/data/data/ch.protonmail.android/

When Chrome attempts to open Proton Mail's private database, Linux checks whether Chrome's process identity is allowed to access the file.

If the file is restricted to Proton Mail's identity, Chrome is denied.

Chrome attempts to read Proton Mail's database
                    |
                    v
          Kernel checks access
                    |
                    v
              Permission denied

The application doesn't need to implement this protection itself. The operating system enforces it.

This is why an app cannot bypass the sandbox simply by writing code that opens another app's private path.

What Changes when you run su?

In your earlier experiment, you ran:

su
ls /data/data/

After switching to root, you could simply list many application directories.

The key change was your process identity:

Ordinary shell
UID = 2000 (commonly)
       |
       v
Access to /data denied

       su

Root shell
UID = 0
       |
       v
Broader filesystem access

Root is privileged Linux identity. It can bypass many ordinary filesystem permission checks that restrict normal users.

However, Android also uses SELinux mandatory access control. Depending on the root configuration and SELinux policy, even a root process may still be restricted from certain operations.

 

 

Buy Me A Coffee

Leave a comment

Your experience on this site will be improved by allowing cookies Cookie Policy