Android Security & Privacy: learning goals
Review a small app's actual data flows: what it collects, where it stores information, what it sends, and when it deletes data. Make a narrow, demonstrable security improvement before preparing a release.
Project setup and scope
Build the mental model
Start from assets and boundaries. A study note may contain personal information even when the app has no login screen. List each asset, the code that can read it, the system or service it crosses, and the user's expectation. Avoid collecting data that the feature does not need.
Server credentials cannot be kept confidential inside a distributed APK. Moving a secret into a resources file, BuildConfig, native code or obfuscation changes its location rather than making a trustworthy server boundary. Keep privileged server operations behind an authenticated backend and apply provider-supported restrictions to public client identifiers.
Choose storage and cryptography based on a threat model. App-private storage limits ordinary cross-app access but does not by itself promise protection against every compromised device or backup exposure. Android Keystore helps manage cryptographic keys; it is not a replacement for access control, lifecycle design, deletion policy or careful cryptographic API use.
Prefer platform-mediated selection when the user chooses a specific file or photo. A picker can grant access to selected content without requesting broad media-library access. A returned URI is an identifier with scoped access, not a filesystem path or unlimited permanent grant. Handle cancellation and decide whether durable access or a controlled local copy is needed.
Choose the right approach
| Need | Approach |
|---|---|
| User chooses one image | Use the system photo picker and handle a null/cancel result. |
| Privileged backend secret | Keep it on a server; never ship it in the app. |
| Ordinary private session data | Use app-private persistence with an explicit backup/deletion policy. |
| Sensitive local encryption key | Evaluate Android Keystore and vetted crypto APIs against the threat model. |
| Diagnostic logging | Use nonpersonal identifiers and remove tokens, notes and sensitive payloads. |
Predict and trace the behavior
Android Security & Privacy
Predict what happens next. Follow the diagram, then explain the change in your own words.
Delivery is a sequence of quality gates
Keep signing keys and credentials outside source control. Widen rollout only after reviewing evidence.
Verify the artifact you will distribute, start with a testing track, then observe feedback before widening delivery.
Explore this general model independently. The lesson sequence below follows its own example.
Prepare: Review application ID, versioning, privacy declarations, and production configuration.
Inventory
Name each collected field, purpose, storage location and deletion behavior.
Worked Kotlin example
import android.net.Uri
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.PickVisualMediaRequest
import androidx.activity.result.contract.ActivityResultContracts.PickVisualMedia
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun PickAttachment(onSelected: (Uri) -> Unit) {
val picker = rememberLauncherForActivityResult(PickVisualMedia()) { uri ->
if (uri != null) onSelected(uri) // Cancel leaves the current note unchanged.
}
Button(onClick = {
picker.launch(PickVisualMediaRequest(PickVisualMedia.ImageOnly))
}) {
Text("Choose image") // Move this label into strings.xml in your app.
}
}
// No broad storage/media permission is needed for this selection flow.
// TODO: decide URI access lifetime, validate content/size, and implement removal.- The launcher belongs to the composition, and launching occurs from a user event. Do not open the picker automatically during recomposition.
- A null result represents cancellation; the callback deliberately leaves the current note untouched.
- Accepting a URI is only the selection boundary. Use ContentResolver for content access, handle revoked/unavailable access, and apply a size/type policy before uploading or copying content.
- If access must survive longer, follow the contract/provider guidance for persistable grants or make a controlled app-private copy; implement deletion for either approach.
Student practice and expected behavior
Audit the notes app. Add one optional user-selected attachment, remove unnecessary permissions, redact sensitive logs, and document a data deletion action. Record the purpose, retention and transmission of every field.
- Cancelling the picker leaves the existing note and attachment unchanged.
- Choosing an image attaches only the selected content; no broad gallery permission prompt appears for this flow.
- An unavailable URI shows a recoverable state instead of crashing or silently uploading a different file.
- Deleting a note removes app-owned attachment data according to your stated policy, while not claiming to erase the user's original photo.
- The source and logs contain no private backend credentials, user note text, session tokens or signing passwords.
Write down the input, expected outcome and observed outcome for each check. Include a screenshot, a short recording or a nonpersonal diagnostic trace appropriate to the behavior you are proving.
Debugging clinic
- An encrypted blob is not a complete privacy policy. Retention, sharing, backups, deletion and SDK behavior still matter.
- Do not convert content:// URIs to guessed filesystem paths or assume every provider gives permanent access.
- Avoid disabling TLS certificate checks to repair a development connection. Correct the endpoint/certificate and isolate development configuration.
- A client-supplied user ID is not server authorization. The backend must verify what the authenticated caller may access.
Instructor prompts
- Ask pairs to draw the path of one attachment from selection to deletion and mark each trust boundary.
- Give students a fake secret in BuildConfig and ask why obfuscating the APK would not establish a server boundary.
- Review a privacy inventory against the actual app flow and installed SDKs; highlight one unverified claim.
Teach-back checkpoint
Quick check and references
Quick check
1. Where does a privileged backend credential belong?
2. What should picker cancellation do in this example?
Continue with the phase capstone after demonstrating the practice checks. Use the official documentation to verify APIs against your project's selected dependency versions.