Mehdi Tmimi Mobile

Mobile Development Chapter 02 · Android · 1 of 2

What happens when you tap an app's icon?

An assistant built your messages app. Tap its icon: your messages appear. Yet none of its code starts the app, and your banking app cannot read the files holding them.

Every app is its own process, under its own Linux user. Android starts each one.

The short answerAndroid starts the app, not your code. It reads the manifest, starts a process running as the app's own Linux user, and opens the screen the manifest names. No other app can open that user's private folder: apps share through Android.

Android opens the screen the manifest names

A Java program starts in main(), a Node script at its first line; an Android app does not start itself. It carries a manifest: the list of its activities, the screens Android can open, and of the permissions it may use.

Tap the icon of an app that is not running: Android opens the activity marked as the launcher, the screen the icon opens. It calls its onCreate(): only then does your screen's code run.

A permission the manifest does not declare is never granted: no dialog even appears.

Your messages app's manifest

AndroidManifest.xml in the built app

<manifest package="com.tmimiexplains.messages"><uses-permission android:name="android.permission.CAMERA"/><application><activity android:name="com.tmimiexplains.messages.MainActivity" android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity></application></manifest>

uses-permission

What the app may use

Declared here, so the app may ask. Not declared: never granted, and no dialog.

activity · LAUNCHER

The screen the icon opens

Android calls its onCreate(). The app never starts itself.

Android starts a process, as the app's own user

At install, Android gives the app its own Linux user, like an account, with a private folder. Both are tied to its package name, the app's unique name.

When you tap the icon, Android starts a process if the app has none: the app running in memory, numbered by its PID. Expo, Flutter and Ionic apps get their own user too, once built. An installed web app (PWA) runs inside Chrome; its data lives in Chrome's folder.

One app, four names

The four names of your messages app, who gives each one, and how long it lasts
Your messages appGiven byLasts
Package namecom.tmimiexplains.messagesyou, in the projectas long as you keep it
Linux useru0_a231Android, at installuntil uninstall; updates keep it
Private folder/data/data/com.tmimiexplains.messagesAndroid, at installuntil uninstall
Process (PID)4127 → 5310Android, at each startuntil the process ends

Coming back reuses a process still in memory: Why does your message sometimes vanish when you come back to an app?

Each start gets a new PID, always as the same user.

Other apps stay out; sharing goes through Android

Your banking app runs as another user, so Linux, the core under Android, keeps it out of your app's folder.

To share, apps go through Android. They use a link that opens another app, a shared folder such as Download, or the share sheet, Android's list of apps to send to. Android checks each exchange.

Go deeper The ways apps share, as you will meet them in a project 1 min
The ways two apps share on Android
The way, and its real nameWhat you see in the project
Share button: an intent, through the Android Sharesheetan <intent-filter> in the receiving app
Links: a deep link; an App Link, which the website vouches foran <intent-filter> with the address
Shared folders: shared storage, through the media store or the system pickersnone for your own files or with a picker; a media permission to read other apps' media
Data an app offers: a content provider; a FileProvider lends one file to one app, for a whilea <provider>
An app's service: a bound servicean exported <service>
Announcements: a broadcasta <receiver>, or one registered in code
Copy and paste: the clipboard, held by Androidnothing to declare

Each one starts with a call to Android, which checks who calls and whether the target accepts.

Two apps could also talk over the network, like any two programs: Android checks only their network permissions, not the conversation.

Who opens what

  • Your messages app runs as u0_a231, and opens its own private folder.
  • The banking app runs as u0_a198. It asks for your folder, and Linux refuses: u0_a198 ≠ u0_a231.
  • To share a message, your app hands it to Android, which gives Chrome a copy.
  • A photo saved to Pictures/ goes through Android, into a shared folder.

Back to your messages app

Android read its manifest, started process 4127 as user u0_a231, and only then called its code. Your banking app runs as u0_a198, so Linux keeps your messages closed to it.

The rule

Your app gets only the permissions its manifest declares, and opens only its own private folder. Everything else goes through Android.

Recap

  1. The app does not start itself. The tap opens the manifest's launcher screen.
  2. A permission not declared is never granted, and no dialog appears.
  3. Each app runs as its own user. Linux keeps its folder closed; apps share through Android.
  4. Each start, a new PID.
    What changes when the app starts again
    When the app starts again
    Package namesame
    Linux usersame
    Private foldersame
    Process (PID)new

With knowledge · in class · 12 minutes

Read the manifest before the code

I build with
  1. Tell the assistant

    Paste it before you describe your app. App already made? Add: “Apply these rules to my project.”

    This app runs on Android.This web app (PWA) runs in Chrome on Android.Package name: com.<yourname>.<app>, never the template's placeholder.Permissions: only those its features use; tell me which feature needs each one.Exported: only the launcher activity.Photos and files: the system photo picker; to hand out a file, the share sheet or the system file picker, never its path.

    In its reply

    Paste the Permissions: line again and ask the assistant why.

  2. Check what it wrote

    The files decide, not the reply.

    • Package name, the app's unique name

      applicationId in Gradle Scripts → build.gradle.kts (Module :app)android.package in app.jsonapplicationId in android/app/build.gradle.ktsappId in capacitor.config.ts and applicationId in android/app/build.gradle: change both

      Ask the assistant to change it now: later, it would be another app. Then uninstall the old app: its icon stays on the phone.

    • Exported, open to other apps

      app → manifests → AndroidManifest.xmlandroid/app/src/main/AndroidManifest.xml

      It exists once npx expo run:android has run.

      Paste the Exported: line again and ask the assistant why.

    • Permissions, in your code

      Search getUserMedia, geolocation, requestPermission (Ctrl+Shift+F)

      Paste the Permissions: line again and ask the assistant why.

  3. Test on your phone

    Run the latest version: the phone decides.

    Needs adb: adb devices lists your phone. Not yet? Before class, just below.

    • Permissions, in Settings

      Settings → Apps → your app → PermissionsChrome → Settings → Site settings → All sites → your site

      Settings lists only what a user can switch off; adb lists them all.In Expo Go you see Expo Go's: test your own build, made by npx expo run:android.The site asks Chrome for each one.

      Paste the Permissions: line again and ask the assistant why.

    • Permissions, with adb

      adb shell "dumpsys package com.<yourname>.<app> | grep -i permission"

      Read the lines under requested permissions:

      Ask the assistant to remove it (READ_MEDIA_IMAGES, MANAGE_EXTERNAL_STORAGE): your private folder and the photo picker need none.Block it (READ_MEDIA_IMAGES, MANAGE_EXTERNAL_STORAGE) with android.blockedPermissions in app.json: your folder and the photo picker need none.

  4. Debrief

    What did you find that you never asked for? Who put it there?

    One answer

    Usually the template's package name, and permission lines that the template or a library adds (AndroidX adds one ending in DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION). Neither you nor the assistant typed them: that is why you read the files and the phone, not only its reply.Usually nothing. If there is a permission, a library's code asked Chrome for it: ask the assistant which one, and why.

Go deeper Every build, side by side 1 min
Where each build sets its package name and its permissions
BuildPackage name (the template's)Permissions and manifest
Java, ComposeapplicationId in app/build.gradle.kts (com.example.…)app/src/main/AndroidManifest.xml
Expoandroid.package in app.json (missing, or com.anonymous.…)android.permissions in app.json, and android.blockedPermissions for what a library adds. The manifest exists once npx expo run:android has made android/. Test your own build, not Expo Go.
FlutterapplicationId in android/app/build.gradle.kts (com.example.…)android/app/src/main/AndroidManifest.xml
IonicappId in capacitor.config.ts and applicationId in android/app/build.gradle, copied once: change both (io.ionic.starter)android/app/src/main/AndroidManifest.xml
PWAnone to write: Chrome installs it from your web manifestnone: the site asks Chrome for each permission; its data lives in Chrome's folder

Try it on your phone · 4 minutes

See the app's user, a new process, a closed folder

These steps need adb, installed once: see Before class, just below.

Before class Install adb 5 min

adb, the Android Debug Bridge, is a command-line tool that sends your laptop's commands to your phone. Turn on Developer options, as in Who draws the pixels of a mobile app?, then USB debugging, and accept the prompt on the phone. Install the Android SDK Platform-Tools; Android Studio already has them, in %LOCALAPPDATA%\Android\Sdk\platform-tools on Windows. adb devices must list your phone. On Windows, inside that folder, type .\adb instead of adb, or add the folder to your PATH.

Copy the commands as they are: the quotes make the filter run on the phone, so the same lines work from Windows, macOS and Linux.

Empty list, or “unauthorized”? Unlock the phone and accept the prompt, try another cable, or install your phone maker's USB driver. No cable? The same lines work on Android Studio's emulator.

  1. Who runs Chrome. Open Chrome, press Home, then list its process.

    adb shell "ps -A -o USER,PID,NAME | grep com.android.chrome$"
    You should seeu0_a160       4116 com.android.chrome

    The first column is Chrome's Linux user, whose number differs from phone to phone; the second is its PID. The final $ keeps only Chrome's own line. Nothing printed? Open Chrome, then run it again.

    This proves Chrome runs as its own Linux user.

  2. A new start, the same user. Stop Chrome with the command form of Force stop. It prints nothing.

    adb shell am force-stop com.android.chrome

    Open Chrome again, press Home, and list its process as in step 1.

    adb shell "ps -A -o USER,PID,NAME | grep com.android.chrome$"
    You should seeu0_a160       4624 com.android.chrome

    This proves Each start gets a new process, always as that user.

  3. Its private folder. Ask the phone's shell to list it.

    adb shell ls /data/data/com.android.chrome
    You should seels: /data/data/com.android.chrome: Permission denied

    This proves The phone's shell, where adb runs your commands, is another Linux user, shell, so Linux refuses it.

Real outputs, captured on 27 October 2026 on an Android 16 emulator (Pixel 7 profile, API 36), the same in PowerShell and cmd. Your user numbers and PIDs will differ.

Quick check

The user taps your app's icon. What tells Android which screen to open?

See the answer

Android starts the app from its manifest. Your source folders, and any main() in them, do nothing until it does.

The assistant's code requests the camera permission, but the manifest has no CAMERA line. What does the user see?

See the answer

What is not declared cannot be granted, and the manifest is fixed when the app is built: add the line, rebuild, and the dialog appears.

Your app must hand one attachment, kept in its private folder, to an email app. What works?

See the answer

The email app runs as another user, so your path stays closed to it, and All files access opens shared storage, never another app's private folder. Through the share sheet, a FileProvider lends that one file to that one app, for a while.

You test your Expo app in Expo Go, then open Settings → Apps to check its permissions. Whose do you find?

See the answer

Your own package and permissions exist only once your app itself is built: a development build (eas build or npx expo run:android) or a store build.

Sources

← All chapters