Bölüm 1: Bu Nedir ve Neden Hayati Önem Taşır?
Android Scoped Storage (Kapsamlı Depolama), Android 10 (API 29) ile tanıtılan ve Android 11 (API 30) ile zorunlu hale getirilen, dosya sistemi erişim paradigmasını kökten değiştiren bir güvenlik mimarisidir. Geleneksel “Global Depolama” modelinde uygulamalar READ_EXTERNAL_STORAGE ve WRITE_EXTERNAL_STORAGE izinleriyle paylaşılan harici depolama alanındaki her dosyaya erişebiliyordu; bu durum veri sızıntısı, kötü amaçlı dosya silme ve kullanıcı gizlilihi ihlali riskleri yaratıyordu. Scoped Storage, “En Az Ayrıcalık Prensibi” (Principle of Least Privilege) ontolojik çerçevesine dayanarak, her uygulamanın kendi özel (app-specific) dizinine (/data/user/0/package_name/) ve kullanıcı tarafından açıkça seçilen medya dosyalarına (MediaStore) sınırlı erişim sağlar. Bu mimari, dosya sistemini bir “ortak havuz” olmaktan çıkarıp, izole edilmiş, sahiplik odaklı bir nesne deposuna dönüştürür. Temel yaklaşım; dosya yollarının (path) yerini ContentProvider tabanlı Uri referanslarının alması, izin modelinin “tüm veya hiç” den “anlık ve bağlamsal” (runtime, scoped) bir modele evrilmesidir.
Bölüm 2: Perde Arkası: Sistem Nasıl Çalışıyor?
Mekanizma, Linux çekirdeğinin Discretionary Access Control (DAC) yetkilendirme modelinin üzerine, Android’in Application Sandbox (Uygulama Kumhavuzu) ve Binder IPC altyapısıyla katmanlanarak inşa edilmiştir. Uygulama kendi paket adıyla eşleşen özel dizinlerde (getExternalFilesDir(), getCacheDir()) herhangi bir izin istemeden tam okuma/yazma yetkisine sahiptir; bu alanlar uygulama silindiğinde sistem tarafından otomatik temizlenir. Paylaşılan medya (Resim, Video, Ses) için MediaStore Content Provider aracılığıyla erişim sağlanır; Android 10’da kendi oluşturduğu medyaya izinssiz, başkalarının medyasına READ_EXTERNAL_STORAGE ile erişim mümkündür. Android 11+ ile birlikte MediaStore yazma işlemleri MediaStore.createWriteRequest() ile kullanıcı onayı (system picker) gerektirir. Belgeler ve diğer dosyalar için Storage Access Framework (SAF) ve ACTION_OPEN_DOCUMENT_TREE intent’leri kullanılarak “Document Provider” üzerinden kalıcı URI izinleri (takePersistableUriPermission) elde edilir. Bu mekanizma, dosya tanıtıcılarının (file descriptors) sürekliliğini ve güvenliğini Binder token’larıyla garanti altına alır.
Bölüm 3: Bilim Dünyası ve Uzmanlar Nasıl İnceliyor?
Scoped Storage uygulamasını yöneten standartlar; Android Compatibility Definition Document (CDD), Android Compatibility Test Suite (CTS) ve Google Play Developer Policy tarafından zorunlu kılınır. CDD Bölüm 7.6.1, harici depolama davranışını ve izin modelini tanımlarken; CTS testleri (android.storage.cts), MediaStore indeksleme tutarlılığını, SAF performansını ve izin geri çağırma (revocation) mekanizmalarını doğrular. Geliştirme metodolojisi; targetSdkVersion seviyesine bağlı davranışsal uyumluluk (compatibility framework) stratejisini benimser: API 29 için requestLegacyExternalStorage="true" bayrağı geçici bir “opt-out” mekanizması sunarken, API 30+ için bu bayrak yok sayılır ve tam zorunluluk devreye girer. Protokol seviyesinde; ContentResolver aracılığıyla ContentProvider sorgulamaları (query, insert, update, delete) SQL benzeri bir arayüzle (selection, selectionArgs, sortOrder) gerçekleştirilir. Dosya meta verileri MediaColumns (DISPLAY_NAME, MIME_TYPE, RELATIVE_PATH, IS_PENDING) standartlarıyla modellenir. Güvenlik denetimleri için AppOpsManager (OP_READ_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE) ve PermissionController sistem servisleri operasyonel kısıtlamaları uygular.
Bölüm 4: Önemli Parametreler ve Karşılaştırma Rehberi
| Parametre | Ölçüt / Değer | Metrik | Stratejik Etki |
|---|---|---|---|
| Erişim Modeli | Yol Tabanlı (Path) -> URI Tabanlı (Content://) | API Seviyesi Geçiş Maliyeti (Saat) | Kod tabanında File nesnesi kullanımının %100 Uri/FileDescriptor ile değiştirilmesini zorunlu kılar. |
| İzin Granülerliği | READ/WRITE_EXTERNAL_STORAGE (Genel) -> READ_MEDIA_IMAGES/VIDEO/AUDIO (Android 13+) |
İzin Reddi Oranı / Kullanıcı Güveni | Kullanıcı “Tüm Dosyalar” yerine “Sadece Fotoğraflar” izni verebildiği için onay oranları artar, Play Store politikası uyumu sağlanır. |
| Uygulama Özel Dizini | getExternalFilesDir(null) -> /Android/data/pkg/ |
Yaşam Döngüsü Bağımlılığı (Otomatik Temizleme) | Veri kalıcılığı riskini ortadan kaldırır; uygulama silinince veri silinir (GDPR/KVKK uyumu). |
| Medya Erişimi | Doğrudan Dosya Sistemi -> MediaStore ContentProvider |
Sorgu Gecikmesi (ms) / İndeksleme Gecikmesi | Medya tarayıcı uygulamalarında CursorLoader/PagingSource zorunluluğu getirir; performans profilin değişir. |
| Belgeler Erişimi | File.listFiles() -> DocumentsContract / SAF |
Kullanıcı Etkileşim Sayısı (Picker Açılma) | Kullanıcı müdahalesi gerektiren “Document Tree” seçimi, arka plan işlemlerini (sync/backup) engeller. |
| Yedekleme/Taşıma | adb backup / cp -r -> BackupAgent / MediaStore Taşıma |
Veri Taşınabilirlik Skoru | Kök erişimsiz cihazlarda tam sistem yedeklemesi imkansızlaşır; bulut tabanlı yedekleme mimarisi şart hale gelir. |
| Geçiş Bayrağı | requestLegacyExternalStorage (API 29) -> Yok (API 30+) |
Teknik Borç (Technical Debt) Süresi | API 29’da 1 yıl süreli “geçiş periyodu” sona erdi; legacy kod yollarının tamamen temizlenmesi zorunludur. |
| MANAGE_EXTERNAL_STORAGE | “Tüm Dosyaları Yönet” Özel İzni (API 30+) | Play Store İnceleme Geçiş Oranı (% < 1) | Sadece dosya yöneticileri, yedekleme/antivirüs uygulamaları için; genel amaçlı uygulamalarda reddedilir. |
| Dosya Sahipliği | UID/GID Tabanlı -> Paket Adı (Package Name) Tabanlı | Çapraz Uygulama Veri Sızıntısı Riski | Uygulama A, Uygulama B’nin Android/data/ altındaki dosyalarını API 30+ da okuyamaz (sandbox kırılmaz). |
| Performans (I/O) | Doğrudan Blok Erişimi -> Binder IPC + FUSE Daemon | Sıralı Okuma/Yazma Bant Genişliği (MB/s) | Küçük dosyalarda %15-30 gecikme artışı; büyük dosyalarda ParcelFileDescriptor ile minimize edilebilir. |
| Gizlilik Etiketi | Cihaz Kimliği (IMEI/Serial) -> Reklam Kimliği (GAID) / Scoped Storage | Kullanıcı Profil Bağlantısı Riski | Dosya meta verilerinden (EXIF konum vb.) kullanıcı profilleme riskini MediaStore temizleme API’leriyle azaltır. |
| Test Stratejisi | Emülatör / Root Cihaz -> Non-Root Fiziksel Cihaz / CTS | Keşfedilen Hata Sayısı / Sürüm | Depolama birimi (Volume) davranışları (SD Kart, USB OTG, Sanal Disk) sadece fiziksel testte doğrulanabilir. |
Bölüm 5: Günlük Hayatta ve Doğada Nerede Karşımıza Çıkar?
Pratik senaryolarda en kritik ayrım, “Üretici” (Producer) ile “Tüketici” (Consumer) uygulamaları arasındadır. Bir kamera uygulaması (Producer), çektiği fotoğrafı MediaStore.Images.Media.insertImage veya ContentResolver.insert ile RELATIVE_PATH = "Pictures/MyApp/" belirterek kaydeder; bu dosya otomatik olarak galeride görünür ve uygulama silinse bile kullanıcı verisi kalır. Bir galeri/düzenleyici uygulaması (Consumer) ise MediaStore sorgulayarak Thumbnail yükler, düzenleme için createWriteRequest ile kullanıcı onayı alır ve ParcelFileDescriptor ile bayt akışı manipüle eder. Belge tarayıcı/bulut senkronizasyon uygulamaları (Örn: Google Drive, Microsoft OneDrive) ACTION_OPEN_DOCUMENT_TREE ile kullanıcının seçtiği bir klasör ağacına kalıcı URI izni (FLAG_PERSISTABLE_URI_PERMISSION) alır ve arka planda DocumentsContract.renameDocument/deleteDocument ile senkronizasyon sağlar. “Tüm Dosyaları Yönet” (MANAGE_EXTERNAL_STORAGE) izni gerektiren nadir senaryolarda (kök dizin tarama, sistem log toplama, cihaz yönetimi MDM), Play Store “Tüm Dosyalar Erişimi” formu doldurularak, ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION intent’i ile kullanıcıyı sistem ayarlarına yönlendirme zorunluluğu doğar. Bu izin reddedildiğinde uygulama “degrade modda” (sadece kendi sandbox’ı) çalışmalıdır.
Bölüm 6: Karşılaşılan Zorluklar ve Pratik Çözümler
En yaygın operasyonel darboğaz, MediaStore indeksleme gecikmesidir (MediaScannerConnection asenkron çalışır); yeni oluşturulan dosyanın MediaStore sorgusunda görünmesi saniyeler sürebilir. Çözüm: MediaScannerConnection.scanFile çağrısı veya IS_PENDING=1 flag’ı ile dosyayı “taslak” olarak işaretleyip, yazma bitince IS_PENDING=0 yaparak anında görünürlük sağlamaktır. İkinci risk, DocumentsContract API’lerinin cihaz üreticisi (OEM) uygulamalarındaki (Samsung My Files, Xiaomi File Manager) DocumentProvider hatalarıdır; örn: renameDocument desteklenmemesi veya FLAG_SUPPORTS_CREATE yanlış bildirilmesi. Çözüm: try-catch bloklarıyla UnsupportedOperationException yakalayıp SAF picker’ı tekrar tetiklemek (fallback). Üçüncü risk, Scoped Storage geçişinde legacy File yollarını Uriye çevirmek için FileProvider kullanımında grantUriPermissions manifest tanımının eksikliği veya FLAG_GRANT_READ_URI_PERMISSION unutulmasıdır. Dördüncü risk, Android 11+ da Android/data ve Android/obb dizinlerinin File API’siyle listelenememesi (listFiles() -> null); çözüm Files.list(Path.of(context.getExternalFilesDir(null).toString())) (Java NIO.2) kullanımıdır ancak bu da sadece kendi paket dizini için geçerlidir. Beşinci risk, kullanıcının “Tüm Dosyalar” iznini sistem ayarlarından iptal etmesi durumunda OnPermissionRevokedListener (API 33+) ile çalışma anında veri erişiminin kesilmesi ve uygulama çökmesini önlemek için ContentResolver sorgularının SecurityException yakalamasıdır.
Bölüm 7: Gelecek Perspektifi ve Yeni Gelişmeler
Android 14 (API 34) ve 15 (VanillaIceCream) ile Scoped Storage modeli “Bölünmüş Depolama” (Partitioned Storage) ve “Sanal Dosya Sistemleri” (Virtual File Systems – VFS) yönünde evrilmektedir. Android 14, MediaStore için MediaCollections (Koleksiyonlar) kavramını getirerek, kullanıcının “Favoriler”, “Arşiv” gibi mantıksal gruplar oluşturmasına ve uygulamaların bu koleksiyonlara yazma izni almasına olanak tanıdı. Android 15’te öne çıkan FileIntegrityManager ve fs-verity entegrasyonu, dosya bütünlüğünü donanım destekli olarak doğrulamayı hedefler. Gelecek 5-10 yılık projeksiyonda; “Kullanıcı Alanı Dosya Sistemi” (FUSE) performans darboğazının, virtio-fs veya erofs (Enhanced Read-Only File System) gibi çekirdek seviyesinde optimize edilmiş sanal dosya sistemleriyle aşılması beklenir. Ayrıca, “Depolama Alanı Yalıtımı” (Storage Isolation), çoklu kullanıcı (Multi-user) ve iş profili (Work Profile) senaryolarında sdcardfs/fuse daemon’larının kullanıcı bazlı namespace izolasyonu sağlayacak şekilde yeniden yazılacaktır. Yapay zeka tabanlı cihaz içi işleme (On-device AI) artışıyla, modellerin ve veri kümelerinin (datasets) MediaStore dışında, getDataDir() veya getNoBackupFilesDir() altındaki özel, şifreli ve yedeklenmeyen alanlarda tutulması standartlaşacaktır. KVKK/GDPR “Unutulma Hakkı” (Right to be Forgotten) gerektiren anlık veri silme operasyonları için MediaStore toplu silme API’leri (delete with IN clause) performans odaklı optimize edilecektir.
Bölüm 8: Merak Edilen Sorular ve Cevaplar
Soru 1: Android 11+ (API 30) hedeflerken requestLegacyExternalStorage="true" manifest bayrağı işe yarar mı?
Cevap: Hayır. Android 11 (API 30) ve üzeri hedeflenen uygulamalarda (targetSdkVersion >= 30) bu manifest özniteliği sistem tarafından tamamen yok sayılır. Uygulama zorunlu olarak Scoped Storage kurallarıyla çalışmak zorundadır. Geçiş stratejisi olarak sadece API 29 (Android 10) hedefleyen geçici sürümlerde işlev görür.
Soru 2: Kullanıcı “Tüm Dosyaları Yönet” (MANAGE_EXTERNAL_STORAGE) iznini verdiğinde uygulama her yere erişebilir mi?
Cevap: Teknik olarak evet, ancak /Android/data/ ve /Android/obb/ dizinlerinin içeriği (diğer paketlerin verileri) yine de Linux DAC izinleri (UID/GID) nedeniyle okunamaz/yazılamaz. Bu izin sadece MediaStore dışındaki klasörler (Download, Documents, kök dizinler) için File API’siyle ham erişim sağlar. Diğer uygulamaların sandbox verilerine erişim yine ContentProvider export edilmeden imkansızdır.
Soru 3: MediaStore ile kaydedilen bir dosyayı File nesnesi ile nasıl okuyabilirim?
Cevap: Doğrudan File yolu (/storage/emulated/0/Pictures/...) ile erişim yasaktır ve FileNotFoundException veya SecurityException fırlatır. ContentResolver.openFileDescriptor(uri, "r") ile ParcelFileDescriptor alınmalı ve ParcelFileDescriptor.AutoCloseInputStream veya FileInputStream(fd.getFileDescriptor()) ile bayt akışı okunmalıdır.
Soru 4: SAF (Storage Access Framework) ile alınan bir klasör (Tree URI) izni uygulama yeniden başladığında nasıl korunur?
Cevap: Activity.onActivityResult içinde alınan treeUri için contentResolver.takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION) çağrılmalıdır. Bu izin, cihaz yeniden başlatılsa bile ContentResolver üzerinden DocumentsContract.buildChildDocumentsUriUsingTree(treeUri, documentId) ile erişime devam ettirir. İzin, kullanıcı “Depolama” ayarlarından uygulamayı silene kadar veya uygulama verisi temizlenene kadar geçerlidir.
Soru 5: Uygulama silindiğinde getExternalFilesDir() altındaki veriler silinir mi? MediaStore altındakiler ne olur?
Cevap: Evet, getExternalFilesDir(), getCacheDir(), getExternalCacheDir() gibi uygulama özel dizinler (package-specific directories) uygulama kaldırıldığında sistem tarafından otomatik ve geri alınamaz şekilde silinir. Ancak MediaStore (Resimler, Videolar, Ses, İndirilenler) veya SAF ile kullanıcı tarafından seçilen klasörlere yazılan dosyalar kullanıcı verisi sayılır ve uygulama silinse bile kalıcı olarak cihazda kalır.
Soru 6: Android 13 (API 33) ile gelen READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO izinleri READ_EXTERNAL_STORAGE yerine nasıl kullanılır?
Cevap: Android 13+ da medya dosyalarına erişim için genel READ_EXTERNAL_STORAGE yerine bu üç ayrı izin (Granular Media Permissions) zorunludur. Uygulama sadece resim okuyorsa READ_MEDIA_IMAGES manifest’e eklenir ve requestPermissions ile istenir. Kullanıcı “İzin Ver” derse sadece resim/video/ses tablolarına (MediaStore.Images/Video/Audio) erişim kazanır. Diğer dosya tipleri (PDF, ZIP vb.) için hâlâ READ_EXTERNAL_STORAGE (veya SAF) gereklidir.
Bölüm 9: Bilmeniz Gereken Temel Terimler
ContentProvider: Uygulamalar arası güvenli veri paylaşımı sağlayan, ContentResolver istemcisiyle SQL benzeri arayüz (query, insert, update, delete) üzerinden erişilen merkezi veri abstraksiyon katmanı. MediaStore ve DocumentsProvider bunların sistem uygulamalarıdır.
Uri (Uniform Resource Identifier): Dosya sistemindeki fiziksel yolu (/storage/...) soyutlayan, content://authority/path formatında, yetki (authority) ve kimlik (ID) içeren, erişim kontrolü (grant/permission) taşıyan opak bir tanımlayıcı.
ParcelFileDescriptor: Bir dosya tanıtıcısını (file descriptor) işlemler arası (IPC) Binder üzerinden güvenli bir şekilde taşımak için kullanılan Parcelable sarmalayıcı sınıfı. ContentResolver.openFileDescriptor sonucunda döner.
Storage Access Framework (SAF): Kullanıcının sistem dosya seçici (Picker) aracılığıyla belirli bir belge veya klasör ağacı için uygulamaya geçici/kalıcı URI izni vermesini sağlayan çerçeve. ACTION_OPEN_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE intent’leriyle tetiklenir.
MediaStore: Android’in medya dosyalarını (Resim, Video, Ses) indekleyen, meta verilerini (EXIF, konum, süre) saklayan ve ContentProvider arayüzüyle sunan sistem veritabanı servisi. MediaScannerConnection ile güncellenir.
FUSE (Filesystem in Userspace) / sdcardfs: Harici depolama birimlerini (SD Kart, Emulated Storage) kullanıcı alanında (userspace) bağlayarak, UID/GID bazlı izin kontrolünü ve Scoped Storage yalıtımını çekirdek modülü olmadan uygulayan sanal dosya sistemi katmanı.
Scoped Storage (Kapsamlı Depolama): Uygulamanın depolama erişimini kendi özel dizini ve kullanıcı onaylı paylaşılan alanlarla sınırlayan, Android 10+ da varsayılan olan gizlilik odaklı dosya sistemi izin mimarisi.
Bölüm 10: Özet ve Çıkarılması Gereken Dersler
Android Scoped Storage, dosya sistemini bir “açık paylaşımlı alan” olmaktan çıkarıp, “sahiplik odaklı, yetki tabanlı, denetlenebilir bir mikro hizmet ekosistemi”ne dönüştüren paradigmatik bir kaydırmadır. Bu mimari; File I/O’sunun ContentResolver/Uri abstraksiyonuna zorunlu geçişi, izin modelinin “kurulum anında genel”den “çalışma anında granular”e evrilmesi ve veri yaşam döngüsünün uygulama yaşam döngüsünden ayrıştırılması (MediaStore kalıcılığı) üçlü stratejik vektörler üzerinde durur. Kurumsal karar vericiler ve mimarlar için yol haritası şöyledir: 1) Kod Tabanı Temizliği: Tüm java.io.File kullanımlarını ContentResolver/DocumentFile/ParcelFileDescriptor ile değiştirme; requestLegacyExternalStorage bayraklarını tamamen kaldırma. 2) İzin Stratejisi: MANAGE_EXTERNAL_STORAGE talep etmemek; READ_MEDIA_* ve SAF ile kullanıcı bağlamında erişim tasarlamak. 3) Performans Mühendisliği: MediaStore toplu işlemler (Batch Operations) ve IS_PENDING mekanizmasıyla indeksleme gecikmesini maskeleme; büyük dosyalarda ParcelFileDescriptor zero-copy akışları kullanma. 4) Test ve Uyumluluk: OEM DocumentProvider hatalarına karşı try-catch fallback’ler ve CTS/ATS test senaryoları ile CI/CD entegrasyonu. 5) Gelecek Hazırlığı: Android 15+ VirtualizationFramework ve fs-verity entegrasyonları için dosya bütünlüğü ve şifreleme katmanlarını (Jetpack Security / Tink) şimdiden mimariye gömme. Scoped Storage, teknik bir zorunluluktan öte, “Gizlilik Tasarımına Göre” (Privacy by Design) ilkesinin mobil ekosistemdeki somutlaştırmasıdır; buna uyum sağlamak hem yasal riski azaltır hem de kullanıcı güvenini sürdürülebilir kılar.