Bölüm 1: Bu Nedir ve Neden Hayati Önem Taşır?
Android Scoped Storage (Kapsamlı Depolama), Android 10 (API 29) ile başlayıp Android 11 (API 30) ve sonrasında zorunlu hale getirilen, dosya sistemi erişim paradigmasını kökten değiştiren bir güvenlik mimarisidir. Geleneksel “External Storage” modelinde uygulamaların READ_EXTERNAL_STORAGE ve WRITE_EXTERNAL_STORAGE izinleriyle kullanıcı dosya sisteminin tamamına (DCIM, Download, Music vb.) serbest erişimi varken, Scoped Storage bu erişimi uygulama özel dizinlerine (getExternalFilesDir()) ve medya koleksiyonlarına (MediaStore) kısıtlamıştır. Ontolojik olarak bu model, “uygulama merkezli” bir veri sahipliği ilkesinden “kullanıcı merkezli” bir veri egemenliği modeline evrimleşir. Metodolojik çerçeve; dosya yollarının (path) yerini content:// URI şemalarının, ham dosya nesnelerinin yerini DocumentFile ve MediaStore API’lerinin almasıyla özetlenir. Temel parametreler; izinsiz erişim engelleme, veri sızıntısı yüzeyinin minimize edilmesi ve uygulama kaldırıldığında veri kalıntısının (orphan data) otomatik temizlenmesidir. Bu yaklaşım, POSIX izin modelinin yetersiz kaldığı mobil ekosistemlerde Mandatory Access Control (MAC) prensiplerinin kullanıcı alanına (user-space) taşınmasını sağlar.
Bölüm 2: Perde Arkası: Sistem Nasıl Çalışıyor?
Scoped Storage mekanizması, Linux çekirdeğinin Discretionary Access Control (DAC) modelinin üzerine, Android’in Application Sandbox ve SELinux politikalarıyla inşa edilen bir soyutlama katmanı ekleyerek çalışır. Fiziksel depolama birimi (F2FS/ext4) tek bir bölüm olarak kalırken, mantıksal erişim FUSE (Filesystem in Userspace) daemonları (sdcardfs veya fuse-daemon) aracılığıyla الوسطe aracılık edilir. Uygulama openFileDescriptor çağrısı yaptığında, vold (Volume Daemon) ve installd servisleri işbirliği içinde UID/GID eşleşmesi, paket adı ve hedef URI yetkisi (grantUriPermission) doğrulanır. Sebep-sonuç ilişkisinde; bir uygulama kendi getExternalFilesDir() dizinine yazma işlemi open() sistem çağrısı seviyesinde doğrudan izin kontrolünden geçerken, MediaStore koleksiyonlarına (Images, Video, Audio) yazma ContentProvider aracılığıyla INSERT işlemiyle gerçekleşir ve bu işlem MediaScanner tarafından indekslenir. Diğer uygulamaların oluşturduğu dosyalara erişim için READ_MEDIA_IMAGES (API 33+) gibi ince taneli (granular) izinler veya Storage Access Framework (SAF) üzerinden kullanıcı etkileşimli ACTION_OPEN_DOCUMENT/ACTION_CREATE_DOCUMENT akışları zorunludur. Bu mekanizma, “Time-of-Check to Time-of-Use” (TOCTOU) saldırı vektörlerini dosya yolu tabanlı yarış koşullarını URI tabanlı kimlik kanıtlamayla ortadan kaldırır.
Bölüm 3: Bilim Dünyası ve Uzmanlar Nasıl İnceliyor?
Scoped Storage uygulamasının standartlaştırması, Android Compatibility Definition Document (CDD) ve Compatibility Test Suite (CTS) tarafından zorunlu kılınır. CDD Bölüm 7.6.1 (External Storage), cihaz üreticilerinin (OEM) Environment.isExternalStorageManager() yeteneğini sadece sistem uygulamaları ve kullanıcı onaylı özel uygulamalar (All files access) için sunmasını şart koşar. Geliştirici metodolojisi; MediaStore API’si (Android Provider Model), Storage Access Framework (SAF – DocumentsProvider arayüzü) ve FileProvider (content:// URI paylaşımı) üçgeni üzerine kuruludur. Ölçüm ve analiz metodolojisi; dumpsys package <pkg> ile izin durumu analizi, logcat ile SecurityException/FileNotFoundException izleme ve sqlite3 ile media.db şema denetimi içerir. Uluslararası normlarda GDPR “Veri Minimizasyonu” (Art. 5/1-c) ve “Tasarımla Gizlilik” (Art. 25) prensipleri, Scoped Storage’ın mimari kararlarıyla birebir örtüşür. ISO/IEC 27001 A.8.1.1 (Varlık Envanteri) ve A.9.2.3 (Yönetimli Erişim Kontrolü) kontrolleri, uygulama bazlı dosya izolasyonu ile doğrulanabilir hale gelir. Google Play Politikası (Developer Policy Center), API 30+ hedefleyen uygulamalar için Scoped Storage uyumluluğunu yayın ön koşulu haline getirmiştir.
Bölüm 4: Önemli Parametreler ve Karşılaştırma Rehberi
| Parametre | Olcut / Deger | Metrik | Stratejik Etki |
|---|---|---|---|
| Erişim Modeli | Yol Tabanlı (Path) -> URI Tabanlı (Content URI) | API Geçiş Türü | TOCTOU risklerinin ortadan kalkması, geçiş maliyeti (Migration Cost) yüksek. |
| İzin Granülerliği | READ/WRITE_EXTERNAL_STORAGE -> READ_MEDIA_IMAGES/VIDEO/AUDIO (API 33+) |
İzin Sayısı / Kapsam | En az ayrıcalık prensibi (Least Privilege) tam uyumu; kullanıcı onay yükü artar. |
| Uygulama Özel Dizini | Android/data/<package>/ & Android/media/<package>/ |
Dizin İzolasyon Seviyesi | Uygulama silinince veri otomatik silinir (No Orphan Data); yedekleme/geçiş zorlaşır. |
| Medya Koleksiyonu | MediaStore (Images, Video, Audio, Downloads) | İndeksleme Gecikmesi (ms) | MediaScanner bağımlılığı; anında görünürlük yok, batch işlemlerde performans darboğazı. |
| SAF (Storage Access Framework) | ACTION_OPEN_DOCUMENT_TREE / CREATE_DOCUMENT |
Kullanıcı Etkileşim Sayısı | Kullanıcı onayı zorunlu (User Consent); arka plan/otomatik işlemler engellenir. |
| All Files Access (MANAGE_EXTERNAL_STORAGE) | Özel İzin (Special Permission) / Play Store Kısıtlamalı | Politik Uyumluluk % | Çoğu uygulama için reddedilir; dosya yöneticileri/antivirüsler hariç kullanım risklidir. |
| FUSE Daemon Gecikmesi | sdcardfs / fuse-daemon Context Switch |
I/O Gecikmesi (µs) | Sıralı okuma/yazmada %5-15 performans cezası; rastgele erişimde daha belirgin. |
| Dosya Sahipliği (Ownership) | UID:GID = App UID : media_rw / sdcard_rw |
DAC/SELinux Etiket Tutarlılığı | Root olmadan cross-app dosya müdahalesi imkansız; forensic analiz zorlaşır. |
| Yedekleme/Transfer | android:allowBackup / BackupAgent / adb backup |
Veri Taşınabilirlik Skoru | Uygulama özel dizinleri adb backup‘e dahil edilmez; tam cihaz klonlama engellenir. |
| Legacy Modu (requestLegacyExternalStorage) | true (API 29) -> Kaldırıldı (API 30+) |
Geçiş Zorunluluğu Tarihi | Geçiş süresi sona erdi; teknik borç (Technical Debt) sıfırlanmalı. |
| Scoped Storage Bypass Riski | MediaStore pending durumu / IS_PENDING=1 |
Yarış Koşulu Penceresi (ms) | Dosya yazılıp commit edilmeden önce diğer uygulamalara görünmez; atomiklik sağlanır. |
| Kullanıcı Deneyimi (UX) | İzin Diyaloğu Sayısı / SAF Picker Görünümü | Görev Tamamlama Oranı (%) | Karmaşık izin akışları kullanıcı kaçışına (Churn) yol açar; tasarım kritik. |
| Güvenlik Denetimi | AppOpsManager / PermissionController Logları |
Denetim İzlenebilirliği | Hangi uygulama hangi dosyaya ne zaman erişti tam kayıt altına alınır. |
Bölüm 5: Günlük Hayatta ve Doğada Nerede Karşımıza Çıkar?
Scoped Storage’ın pratik yansımaları, medya düzenleme uygulamaları, ofis paketleri, dosya yöneticileri ve IoT ağ geçidi uygulamalarında en yoğun görülür. Bir fotoğraf düzenleme uygulaması (ör. Snapseed/PicsArt benzeri) senaryosunda; kullanıcı galeriden fotoğraf seçer (SAF ACTION_OPEN_DOCUMENT -> takePersistableUriPermission), uygulama işler ve MediaStore.Images.Media.insertImage ile yeni dosyayı “Pictures” koleksiyonuna yazar. Bu akışta FileDescriptor kullanımı ParcelFileDescriptor.MODE_READ_WRITE ile sağlanır. Kritik vaka analizi: Android 11’e güncelleme yapan bir e-tiket uygulaması, Download/Tickets klasörüne yazılan PDF’leri File nesnesiyle okuyamamıştır; çözüm MediaStore.Downloads koleksiyonuna ContentResolver.query ile DISPLAY_NAME filtresi uygulayarak InputStream almak olmuştur. IoT senaryosunda; akıllı ev hub’ının firmware güncelleme dosyalarını Android/data/com.hub.firmware/files/firmware/ altına indirmesi, kullanıcı müdahalesi olmadan FileProvider ile OTA modülüne paylaşılması örneği, uygulama arası güvenli veri akışını gösterir. Hatalı senaryo: Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) kullanarak FileOutputStream açmaya çalışan eski kod tabanları EACCES (Permission denied) ile çöker; bu, DocumentFile.fromTreeUri ile dizin oluşturup createFile yapılarak aşılır.
Bölüm 6: Karşılaşılan Zorluklar ve Pratik Çözümler
En kritik operasyonel darboğaz, MediaStore ile büyük dosya (örn. 4K video > 4GB) yazımında ContentResolver.openOutputStream performans düşüşüdür; çözüm MediaStore.createWriteRequest ile toplu izin alıp ParcelFileDescriptor üzerinden tamponlu (buffered) yazım yapmaktır. Risk faktörü: ACTION_OPEN_DOCUMENT_TREE ile alınan dizin izni (persistable URI), cihaz yeniden başlatıldığında ContentResolver.takePersistableUriPermission ile yenilenmezse erişim kaybolur; bu “Silent Permission Loss” hatası kullanıcıya bildirimsiz veri kaybı riski yaratır. Hata modu: DocumentFile soyutlaması File API’sine benzese de delete(), renameTo(), listFiles() işlemleri DocumentsProvider implementasyonuna (OEM’e) bağlı olarak tutarsız davranır (örn. Samsung vs. Pixel rename davranışı farkı). Proaktif çözüm: File API’sini tamamen terk edip ContentResolver + ContentValues + DocumentFile üçlüsünü standartlaştırmak. Uzun vadeli risk: Google Play’in MANAGE_EXTERNAL_STORAGE politikasının sertleşmesi (2023/2024 güncellemeleri) ile “Dosya Yöneticisi” olmayan uygulamaların bu izni alması neredeyse imkansız hale gelmiştir; bu da legacy kod tabanına sahip kurumsal uygulamaların “Vendor Lock-in” veya “Technical Bankruptcy” riskiyle karşı karşıya kalmasına neden olur. Telafisi zor hata: Kullanıcı Settings > Apps > All Files Access menüsünden izni manuel kapatırsa uygulama SecurityException fırlatır ve çöker; OnBackInvokedDispatcher ile izin durumu dinlenip graceful degradation (sadece okuma modu) sağlanmalıdır.
Bölüm 7: Gelecek Perspektifi ve Yeni Gelişmeler
Android 14 (API 34) ve 15 (VanillaIceCream) ile gelen geliştirmeler, Scoped Storage’ı “Medya” odaklıdan “Belge” odaklı bir modele genişletmektedir. Photo Picker (MediaPicker) API’si, uygulamaların READ_MEDIA_IMAGES izni istemeden sistem UI’si üzerinden güvenli medya seçimini sağlamak için standart hale getirildi; bu “Zero-Permission” erişim modeli, izin yüzeyini sıfıra indiriyor. Android 15’te Virtualized Storage (Sanallaştırılmış Depolama) projeleri (Project Mainline modülü olarak Storage modülü), FUSE daemonını kullanıcı alanından (userspace) çekirdek alanına (kernel – fuse_passthrough) taşıyarak context-switch maliyetini %40-60 azaltmayı hedefliyor. Gelecek 5-10 yillik projeksiyonda; dosya sisteminin tamamen ContentProvider arkasına gizlenmesi, POSIX open/read/write çağrılarının io_uring tabanlı asenkron ContentResolver API’leriyle değiştirilmesi ve “App-Specific External Storage”ın şifreli container (CE/DE keys) içinde tam izole edilmesi öngörülür. Cross-platform (ChromeOS, Android Automotive, WearOS) tutarlılık için StorageManager API’leri MediaStore şemasıyla birleştirilecek. Yapay zeka odaklı “On-Device ML” modellerinin (örn. MediaStore’da IS_FAVORITE, GENERATION_ADDED sütunları) dosya meta verilerini anlamsal olarak zenginleştirmesi, dosya arama ve erişim kontrol listelerini (ACL) dinamik politikalarla (Attribute-Based Access Control – ABAC) yönetmeye iter.
Bölüm 8: Merak Edilen Sorular ve Cevaplar
Soru 1: Neden File nesnesi ile Environment.getExternalStoragePublicDirectory() kullanarak dosya yazamıyorum?
Cevap: Android 10+ (API 29+) bu yolu salt okunur (read-only) hale getirdi; Android 11+ (API 30+) ise File nesnesi üzerinden yazma işlemlerine EACCES (Permission denied) döndürerek tamamen engelledi. Yazma için MediaStore koleksiyonuna ContentResolver.insert() veya SAF ile DocumentFile.createFile() kullanmalısınız.
Soru 2: MANAGE_EXTERNAL_STORAGE (All Files Access) iznini almak için Play Store’onay süreci nasıl işler?
Cevap: Google Play, bu izni sadece “Dosya Yöneticisi”, “Antivirüs”, “Yedekleme/Senkronizasyon”, “Belge Tarayıcı” gibi çekirdek işlevi dosya yönetimi olan uygulamalara verir. Başvuru formunda (Play Console -> App Content -> All files access) kullanıcı senaryosu videosu, gizlilik politikası ve işlevsel gereklilik kanıtı zorunludur. Reddedilme oranı %90’ın üzerindedir.
Soru 3: Kullanıcı ACTION_OPEN_DOCUMENT_TREE ile verdiği dizin izni cihaz yeniden başlatıldığında neden kayboluyor?
Cevap: takePersistableUriPermission(uri, flags) çağrısı onActivityResult veya ActivityResultCallback içinde mutlaka yapılmalıdır. Bu çağrı yapılmazsa izin sadece o oturum (session) için geçerlidir. Ayrıca flags parametresine FLAG_PERSIST_READ_URI_PERMISSION | FLAG_PERSIST_WRITE_URI_PERMISSION eklenmelidir.
Soru 4: MediaStore ile büyük bir video dosyası yazarken OutOfMemoryError veya ANR alıyorum, neden?
Cevap: ContentResolver.openOutputStream(uri) varsayılan olarak tamponlu (buffered) bir akış döndürmez. Dosyayı parçalar halinde (chunked) yazmak için ParcelFileDescriptor alıp FileOutputStream üzerine BufferedOutputStream (örn. 128KB-1MB tampon) sararak yazım yapmalı ve MediaStore IS_PENDING=1 ile başlatıp işlem bitince IS_PENDING=0 yapmalısınız.
Soru 5: Uygulama özel dizini (Android/data/com.pkg/files) kullanıcıya dosya yöneticisinde görünmüyor, nasıl paylaşırım?
Cevap: Bu dizin Android 11+ da diğer uygulamalardan ve dosya yöneticilerinden gizlidir (izole edilmiştir). Kullanıcının erişebilmesi için dosyayı MediaStore.Downloads veya Documents koleksiyonuna kopyalamanız (copy) veya FileProvider ile content:// URI’si üretip Intent.ACTION_SEND/ACTION_VIEW ile paylaşmanız gerekir.
Soru 6: requestLegacyExternalStorage="true" manifest bayrağı artık işlemiyor mu?
Cevap: Evet, Android 11 (API 30) ve üzeri bu bayrağı tamamen yok sayar. Uygulamanız targetSdkVersion 30+ ise Scoped Storage zorunludur. Geçiş yapmamış eski kod tabanları bu API seviyesinde çökecektir.
Bölüm 9: Bilmeniz Gereken Temel Terimler
Content URI (İçerik URI’si): content://authority/path formatında, dosya sistem yolu yerine veri sağlayıcı (ContentProvider) tarafından yönetilen, izin kontrolü ve yaşam döngüsü yönetimi içeren soyut bir veri adresidir.
MediaStore: Android’in medya dosyalarını (Resim, Video, Ses) indeksleyen, sorgulamaya ve koleksiyonlara (Collections) göre organize eden merkezi ContentProvider veritabanı şemasıdır (media.db).
Storage Access Framework (SAF): Kullanıcı etkileşimli dosya/dizin seçimi (ACTION_OPEN_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE) ve uzaktan dosya sistemi erişimi (DocumentsProvider) için standartlaştırılmış çerçeve API’sidir.
FUSE Daemon (sdcardfs/fuse-daemon): Kullanıcı alanında çalışan, fiziksel depolama blok cihazını mantıksal görünüme (emulated storage) çeviren, UID/GID bazlı izin zorlamasını yapan dosya sistemi arabirimi servisidir.
Scoped Storage (Kapsamlı Depolama): Uygulamaların depolama alanına erişimini, kendi özel dizinleri ve kullanıcı onayıyla belirli medya/belge koleksiyonlarıyla sınırlayan, Android 10+ da başlayan zorunlu güvenlik mimarisidir.
Persistable URI Permission (Kalıcı URI İzni): takePersistableUriPermission ile uygulama süreci öldükten ve cihaz yeniden başlatıldktan sonra da geçerli kılınan, SAF üzerinden alınan geçici izinlerin kalıcı hale getirilmesidir.
Bölüm 10: Özet ve Çıkarılması Gereken Dersler
Android Scoped Storage, dosya sistemi güvenliğini “eklenti” olmaktan çıkarıp “mimari tasarım ilkesi” haline getiren bir paradigma kaymasıdır. Analizler, geçiş sürecinin teknik borç (technical debt) temizleme maliyetinin yüksek olduğunu; ancak uzun vadede veri sızıntısı risklerinin (CVE-2019-2215 türü kernel exploit’lerin etkisini azaltma), GDPR/KVKK uyumluluğunun “tasarımla gizlilik” (privacy by design) seviyesine taşındığını ve uygulama kaldırma sonrası veri kirletmesinin (orphan data) sıfırlandığını kanıtlamaktadır. Karar vericiler için yol haritası şöyledir: 1) Legacy Kod Sıfırlama: File API’sini ContentResolver/DocumentFile ile tamamen değiştirme (Strangler Fig Pattern). 2) İzin Minimizasyonu: READ_MEDIA_* izinleri yerine Photo Picker / SAF kullanarak “Zero Permission” hedefleme. 3) Performans Mühendisliği: Büyük dosya I/O için ParcelFileDescriptor + io_uring (API 34+) / AsynchronousSocketChannel tabanlı akışları benimseme. 4) Politika Takibi: Play Console “All Files Access” reddedilme riskine karşı mimariyi SAF/MediaStore’e kilitleme. 5) Gelecek Kanıtlama: Virtualized Storage (Android 15+) ve ABAC modelleri için soyutlama katmanı (Repository Pattern) yeterliliğini test etme. Scoped Storage bir engel değil; güvenilir, denetlenebilir ve ölçeklenebilir mobil ekosistemlerin altyapı taşıdır; buna uyum sağlamak artık bir tercih değil, piyasa hayatta kalma şartıdır.