Security & Performance

Protect user data and deliver fast, responsive Android apps

Security Encryption ProGuard Performance

Table of Contents

Overview

Production Android apps must protect sensitive data and run smoothly on devices ranging from budget phones to flagships. Security and performance are not optional — they affect user trust, Play Store ratings, and retention.

Security Layer Performance Layer ────────────── ───────────────── HTTPS + certificate pinning Avoid main thread blocking Encrypted storage RecyclerView + paging ProGuard / R8 obfuscation Image caching + compression Secure API tokens Memory leak prevention Least-privilege permissions Profiling with Android Studio
AreaGoalTool / Technique
SecurityProtect data in transit and at restTLS, EncryptedSharedPreferences, Keystore
Code protectionObfuscate release buildsR8 / ProGuard
MemoryAvoid leaks and OOM crashesLeakCanary, lifecycle-aware components
PerformanceFast startup, smooth UIProfiler, Baseline Profiles, lazy loading

1App Security Basics

Android app security starts with fundamental practices — secure storage, minimal permissions, network safety, and never hardcoding secrets in source code.

Security principles

  • Defense in depth — multiple layers of protection
  • Least privilege — request only permissions you need
  • Never trust client input — validate on server too
  • Assume device can be compromised — don't store plaintext secrets

Don't hardcode secrets

Kotlin — Bad vs good// BAD — API key in source code (can be extracted from APK) const val API_KEY = "sk_live_abc123secret" // BETTER — load from BuildConfig (still extractable, but not in Git) // build.gradle.kts: buildConfigField("String", "API_KEY", "\"${project.findProperty("API_KEY")}\"") // BEST — short-lived tokens from your backend after user auth suspend fun getApiToken(): String = authRepository.fetchSessionToken()

Network security config

XML — res/xml/network_security_config.xml<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="false"> <trust-anchors> <certificates src="system" /> </trust-anchors> </base-config> </network-security-config>
XML — AndroidManifest.xml<application android:networkSecurityConfig="@xml/network_security_config" android:usesCleartextTraffic="false" ... >

Secure SharedPreferences

Kotlin — EncryptedSharedPreferences// dependency: androidx.security:security-crypto:1.1.0-alpha06 val masterKey = MasterKey.Builder(context) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .build() val securePrefs = EncryptedSharedPreferences.create( context, "secure_prefs", masterKey, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM ) securePrefs.edit().putString("auth_token", token).apply()

Security checklist

CheckAction
HTTPS onlyDisable cleartext traffic
Sensitive prefsUse EncryptedSharedPreferences
Exported componentsSet android:exported="false" unless needed
Debug logsRemove or disable in release builds
Root detectionWarn for banking/high-security apps

2Data Encryption

Encryption protects data at rest on the device. Use Android Keystore for keys and AES encryption for files, databases, and sensitive user information.

Android Keystore

Kotlin — Generate key in Keystorefun generateSecretKey(): SecretKey { val keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore" ) keyGenerator.init( KeyGenParameterSpec.Builder( "my_app_key", KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setUserAuthenticationRequired(false) .build() ) return keyGenerator.generateKey() }

Encrypt and decrypt strings

Kotlin — EncryptionHelper.ktclass EncryptionHelper(context: Context) { private val keyAlias = "app_encryption_key" private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } init { if (!keyStore.containsAlias(keyAlias)) generateKey() } fun encrypt(plainText: String): String { val cipher = Cipher.getInstance("AES/GCM/NoPadding") cipher.init(Cipher.ENCRYPT_MODE, getKey()) val iv = cipher.iv val encrypted = cipher.doFinal(plainText.toByteArray(Charsets.UTF_8)) return Base64.encodeToString(iv + encrypted, Base64.DEFAULT) } fun decrypt(encryptedText: String): String { val decoded = Base64.decode(encryptedText, Base64.DEFAULT) val iv = decoded.copyOfRange(0, 12) val encrypted = decoded.copyOfRange(12, decoded.size) val cipher = Cipher.getInstance("AES/GCM/NoPadding") val spec = GCMParameterSpec(128, iv) cipher.init(Cipher.DECRYPT_MODE, getKey(), spec) return String(cipher.doFinal(encrypted), Charsets.UTF_8) } private fun getKey(): SecretKey { return (keyStore.getEntry(keyAlias, null) as KeyStore.SecretKeyEntry).secretKey } }

SQLCipher for encrypted Room database

Kotlin — Encrypted Room (concept)// For highly sensitive local data, use SQLCipher with Room // implementation("net.zetetic:android-database-sqlcipher:4.5.4") val passphrase = SQLiteDatabase.getBytes("user_passphrase".toCharArray()) val factory = SupportFactory(passphrase) Room.databaseBuilder(context, AppDatabase::class.java, "secure_db.db") .openHelperFactory(factory) .build()

What to encrypt

DataRecommended Approach
Auth tokensEncryptedSharedPreferences
User credentialsNever store passwords — use tokens
PII in databaseRoom + SQLCipher or field-level encryption
Files (PDFs, images)EncryptedFile API (Jetpack Security)
Network trafficHTTPS/TLS (transport encryption)

3ProGuard

R8 (successor to ProGuard) shrinks, obfuscates, and optimizes release builds. It removes unused code, renames classes/methods, and reduces APK size — making reverse engineering harder.

Enable R8 in Gradle

Kotlin — app/build.gradle.ktsandroid { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } }

proguard-rules.pro

Text — proguard-rules.pro# Keep data classes used by Gson -keep class com.example.myapp.model.** { *; } # Retrofit -keepattributes Signature, InnerClasses, EnclosingMethod -keepclassmembers,allowshrinking,allowobfuscation interface * { @retrofit2.http.* <methods>; } # Room -keep class * extends androidx.room.RoomDatabase -keep @androidx.room.Entity class * # Keep Parcelable creators -keepclassmembers class * implements android.os.Parcelable { public static final ** CREATOR; } # Remove logging in release -assumenosideeffects class android.util.Log { public static *** d(...); public static *** v(...); }

Keep rules for libraries

Kotlin — Common keep rules# Gson — keep fields for serialization -keepattributes *Annotation* -keepclassmembers class * { @com.google.gson.annotations.SerializedName <fields>; } # Firebase / Crashlytics — usually auto-included via library consumer rules -keep class com.google.firebase.** { *; } # Hilt / Dagger — generated code kept automatically with correct setup

Test release builds

Always test a minified release build before publishing. R8 can strip classes used via reflection (Gson, Retrofit, Room) if keep rules are missing — causing runtime crashes that don't appear in debug builds.

4Secure APIs

API security ensures data traveling between your app and backend is authenticated, encrypted, and resistant to tampering. Use HTTPS, token-based auth, and certificate pinning for sensitive apps.

HTTPS with OkHttp

Kotlin — Secure Retrofit clientval okHttpClient = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .addInterceptor { chain -> val request = chain.request().newBuilder() .addHeader("Authorization", "Bearer ${tokenProvider.getToken()}") .addHeader("Accept", "application/json") .build() chain.proceed(request) } .addInterceptor(HttpLoggingInterceptor().apply { level = if (BuildConfig.DEBUG) Level.BODY else Level.NONE }) .build()

Certificate pinning

Kotlin — Pin server certificateval certificatePinner = CertificatePinner.Builder() .add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") .build() val client = OkHttpClient.Builder() .certificatePinner(certificatePinner) .build()

Token refresh pattern

Kotlin — Authenticator for 401 refreshclass TokenAuthenticator( private val tokenManager: TokenManager ) : Authenticator { override fun authenticate(route: Route?, response: Response): Request? { if (responseCount(response) >= 2) return null // avoid infinite loop val newToken = runBlocking { tokenManager.refreshToken() } ?: return null return response.request.newBuilder() .header("Authorization", "Bearer $newToken") .build() } }

API security checklist

PracticeWhy
HTTPS onlyEncrypts data in transit
Short-lived JWT tokensLimits damage if token stolen
Refresh token rotationInvalidate compromised sessions
Certificate pinningPrevents MITM with fake certs
Disable logging in releasePrevents token leakage in Logcat
Validate SSL certificatesNever override hostname verification

5Memory Optimization

Memory leaks and excessive allocations cause slowdowns, ANRs, and crashes. Use lifecycle-aware components, recycle bitmaps properly, and detect leaks with profiling tools.

Common memory leaks

Leak SourceFix
Static reference to ActivityUse Application context or WeakReference
Listener not removedUnregister in onDestroy()
Coroutine without scopeUse viewModelScope / lifecycleScope
Large bitmap in memoryDownsample, use Coil/Glide caching
Fragment holding Activity refUse viewLifecycleOwner

Load bitmaps efficiently

Kotlin — BitmapFactory.inSampleSizefun decodeSampledBitmap(path: String, reqWidth: Int, reqHeight: Int): Bitmap { return BitmapFactory.Options().run { inJustDecodeBounds = true BitmapFactory.decodeFile(path, this) inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight) inJustDecodeBounds = false BitmapFactory.decodeFile(path, this) } } fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int { val (height, width) = options.outHeight to options.outWidth var inSampleSize = 1 if (height > reqHeight || width > reqWidth) { val halfHeight = height / 2 val halfWidth = width / 2 while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) { inSampleSize *= 2 } } return inSampleSize }

Coil for image loading

Kotlin — Coil with memory cache// implementation("io.coil-kt:coil:2.5.0") binding.imageView.load(imageUrl) { crossfade(true) size(300, 300) // resize to view size — saves memory memoryCachePolicy(CachePolicy.ENABLED) diskCachePolicy(CachePolicy.ENABLED) }

LeakCanary (debug only)

Kotlin — Detect memory leaks// debugImplementation("com.squareup.leakcanary:leakcanary-android:2.13") // Auto-installs in debug builds — shows notification when leak detected class MyApplication : Application() { // LeakCanary initializes automatically — no code needed }

6Performance Tuning

Performance tuning targets startup time, UI smoothness (60fps), battery usage, and network efficiency. Profile before optimizing — measure, don't guess.

Android Studio Profiler

  1. View → Tool Windows → Profiler
  2. CPU — find methods consuming main thread time
  3. Memory — track allocations and garbage collection
  4. Energy — identify battery-draining operations
  5. Network — monitor request frequency and payload size

Main thread rules

Kotlin — Keep main thread free// NEVER on main thread: // - Network calls // - Database queries (large) // - File I/O // - Heavy JSON parsing // - Bitmap decoding viewModelScope.launch { val data = withContext(Dispatchers.IO) { repository.fetchAndParse() // background } _uiState.value = UiState.Success(data) // back on main }

RecyclerView performance

Kotlin — Optimize RecyclerViewrecyclerView.apply { setHasFixedSize(true) setItemViewCacheSize(20) recycledViewPool.setMaxRecycledViews(VIEW_TYPE_ITEM, 15) } // Use DiffUtil instead of notifyDataSetChanged() class TaskDiffCallback : DiffUtil.ItemCallback<Task>() { override fun areItemsTheSame(old: Task, new: Task) = old.id == new.id override fun areContentsTheSame(old: Task, new: Task) = old == new } adapter.submitList(newList) // ListAdapter + DiffUtil

App startup optimization

  • Defer non-critical init to background (App Startup library)
  • Lazy-load heavy SDKs (analytics, ads) after first screen
  • Use Baseline Profiles for faster code execution
  • Avoid heavy work in Application.onCreate()
  • Measure with Macrobenchmark startup tests

Performance metrics (Play Vitals)

MetricTargetHow to Improve
Cold start< 2 secondsDefer init, Baseline Profiles
ANR rate< 0.5%Move work off main thread
Frame render time< 16ms (60fps)Reduce overdraw, optimize layouts
Crash-free rate> 99%Fix leaks, handle edge cases
Battery drainLow background usageWorkManager constraints, batch network

7Hands-On Exercises

1

Apply security basics — disable cleartext traffic, use EncryptedSharedPreferences for auth token storage.

2

Implement data encryption with Android Keystore — encrypt/decrypt a sensitive string.

3

Enable ProGuard/R8 for release. Add keep rules for Gson models and test the release APK.

4

Configure a secure API client with Bearer token interceptor. Disable HTTP logging in release.

5

Fix a memory leak — use LeakCanary in debug and resolve a static Activity reference.

6

Profile your app with Android Studio Profiler. Move one blocking operation off the main thread.

7

Bonus: Optimize a RecyclerView with DiffUtil, image downsampling, and measure scroll FPS improvement.

Security & Performance MCQ Practice

10 Basic MCQs 10 Advanced MCQs

10 Basic Security & Performance MCQs

1

ProGuard/R8?

ADebug logging
BShrink, obfuscate, optimize release bytecode
CLayout editor
DCamera
Explanation: R8 default in Android Gradle Plugin release builds.
2

HTTPS for APIs?

ASlower illegal
BOptional always
CEncrypts data in transit
DLocalhost only
Explanation: Never send secrets over plain HTTP in production.
3

Android Keystore?

ALogcat
BSharedPreferences
CSQLite
DSecure hardware-backed key storage
Explanation: Store encryption keys and biometric auth keys.
4

Memory leak on Android?

ARetained object preventing GC of unused memory
BFast performance
CGradle feature
DRequired pattern
Explanation: Common: static Activity reference, listener not unregistered.
5

StrictMode detects?

ARelease crashes
BMain thread policy violations in debug
CNetwork speed
DBattery only
Explanation: diskRead, networkOnMainThread penalties in debug.
6

Don't store API keys?

ASafe in comments
BSafe in strings.xml always
CPlain text in APK — extractable via reverse engineering
DSafe in Git public
Explanation: Use backend proxy or remote config with auth.
7

ANR means?

AAPI Not Ready
BAutomatic Network Retry
CAd Network Rule
DApplication Not Responding — main thread blocked
Explanation: UI frozen ~5 seconds triggers ANR dialog.
8

EncryptedSharedPreferences?

AAES encrypted key-value storage
BPublic prefs
CNetwork cache
DLayout
Explanation: Jetpack Security crypto for sensitive tokens.
9

LeakCanary?

AAd blocker
BDebug library detecting memory leaks
CProGuard
DLint
Explanation: Shows notification when activity leaked.
10

Baseline profile improves?

AScreen brightness
BNetwork latency only
CApp startup and critical path performance
DPermissions
Explanation: AOT compilation hints from Macrobenchmark.

10 Advanced Security & Performance MCQs

11

Certificate pinning?

ADisable TLS
BTrust only known server certs in OkHttp
CUse HTTP
DRoom feature
Explanation: Mitigate MITM — pin SPKI in CertificatePinner.
12

Root detection?

ARequired all apps
BAlways block app
CSafetyNet/Play Integrity check device integrity
DDeprecated entirely
Explanation: High-security apps may restrict rooted devices.
13

BiometricPrompt?

AManifest permission only
BCustom ImageView only
CNo crypto
DSecure fingerprint/face auth using Keystore
Explanation: CryptoObject binds auth to key use.
14

Systrace/Perfetto?

ASystem-wide performance tracing
BSQL trace
CAd trace
DLint
Explanation: Analyze frame drops and thread scheduling.
15

R8 keep rules?

ARemove all code
B-keep classes from obfuscation/removal
CDebug only ban
DNetwork
Explanation: proguard-rules.pro for reflection, Parcelable, Retrofit models.
16

WebView security?

AIgnore updates
BAllow all JavaScript from any URL
CDisable file access, validate URLs, HTTPS, update WebView
DRoot WebView
Explanation: WebView vulnerabilities historically significant.
17

Heap dump analysis?

AADB install
BLogcat only
CGradle
DAndroid Studio Profiler memory heap dump
Explanation: Find retained objects causing OOM.
18

Battery optimization impact?

ADoze limits background work — use WorkManager
BNo effect
CMore CPU always
DBan background
Explanation: Respect App Standby buckets and foreground service rules.
19

SQL injection prevention Room?

AString concat SQL
BParameterized queries via Room/DAO
CRaw user input in query
DNo SQL
Explanation: Room uses prepared statements — avoid raw concatenation.
20

App size optimization?

ADuplicate libraries
BAdd more PNGs
CAAB splits, vector icons, R8 shrink, remove unused resources
DIgnore
Explanation: Android Size Analyzer suggests reductions.
Click an option to select, then check answers.

Security & Performance Interview Q&A

15 topic-focused questions for interviews and revision.

1Secure user authentication tokens.hard
Answer: EncryptedSharedPreferences or Keystore; never plain SharedPreferences; short-lived tokens with refresh.
2ProGuard/R8 setup.medium
Answer: isMinifyEnabled true release; proguard-rules.pro keep rules for models, Retrofit, Parcelable.
3Prevent memory leaks.medium
Answer: No static Activity; unregister listeners; ViewModel not holding View; null Fragment binding onDestroyView.
4Why ANR happens.easy
Answer: Long work on main thread — network, disk, heavy computation; move to background.
5HTTPS certificate pinning overview.hard
Answer: OkHttp CertificatePinner.Builder.add("api.example.com", "sha256/...").build()
6Profile app startup.medium
Answer: Android Studio Profiler, Macrobenchmark, Baseline Profile generation.
7Optimize RecyclerView performance.medium
Answer: DiffUtil, stable IDs, setHasFixedSize, avoid heavy bind work, image loading libraries.
8Secure API key handling.hard
Answer: Backend holds secrets; app uses authenticated API; never embed production keys in APK.
9Encrypted database.hard
Answer: SQLCipher or Room with encrypted SupportFactory from Jetpack Security.
10Detect debug vs release security.medium
Answer: Disable logging sensitive data in release; BuildConfig.DEBUG checks.
11WebView best practices.medium
Answer: load only trusted URLs; set javaScriptEnabled carefully; use WebViewClient shouldOverrideUrlLoading.
12Reduce APK/AAB size.medium
Answer: Enable shrinkResources, WebP vectors, feature modules, analyze dependency bloat.
13Play Integrity use case.hard
Answer: Verify app genuine before sensitive transactions.
14StrictMode example setup.easy
Answer: if (BuildConfig.DEBUG) StrictMode.enableDefaults()
15Performance monitoring production.medium
Answer: Firebase Performance, Crashlytics, Android vitals ANR/crash rate dashboards.