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 dönüştüren bir güvenlik mimarisidir. Temel doğasına bakıldığında, bu model “tüm dosya sistemine serbest erişim” (Discretionary Access Control – DAC) prensibinden, “yalnızca sahiplik yapılan veya kullanıcı onayı verilen veriye erişim” (Mandatory Access Control / Capability-based Security) prensibine evrilmiştir. Temel parametreler; uygulama özel dizinleri (getExternalFilesDir()), medya koleksiyonları (MediaStore), indirilen dosyalar (Downloads) ve Doküma Sağlayıcı çerçevesi (SAF) üzerinden tanımlanır. Metodolojik yaklaşım, veri gizliliğini (Privacy by Design) ve en az ayrıcalık ilkesini (Principle of Least Privilege) merkeze alarak, uygulamaların birbirlerinin verilerine veya kullanıcı hassas verilerine (konum, meta veri) izinsiz erişimini engellemeyi hedefler. Bu mimari, depolama birimini uygulama sandboxesinden (kum havuzu) ayırarak, veri sahipliğini kullanıcıya ve işletim sistemine devretmiştir.
Bölüm 2: Perde Arkası: Sistem Nasıl Çalışıyor?
Mekanizmanın mühendislik isleyişi, Linux çekirdeğinin DAC yetenekleri (UID/GID) üzerine inşa edilmiş Android Uygulama Sandbox (UID yalıtımı) ile birleştirilmiş bir katmanlı izin motoruna dayanır. Android 10’da requestLegacyExternalStorage=true ile geçiş süreci sunulmuşken, Android 11’de bu bayrak kaldırılarak zorunlu geçiş sağlanmıştır. Çalışma prensibi şu üç eksene dayanır: 1) Uygulama Özel Dizinler: Android/data/package_name/ yolu altına yazma için herhangi bir izin gerekmez; silme işlemi uygulama kaldırıldığında otomatik gerçekleşir (Sahiplik Modeli). 2) Medya Depolama (MediaStore): Resim, video, ses dosyaları için MediaStore content provider üzerinden erişim; yazma için READ_EXTERNAL_STORAGE (Android 10) veya hiç izin (Android 11+ kendi dosyaları), başkalarının dosyaları için READ_MEDIA_IMAGES/VIDEO/AUDIO (Android 13+) gerekir. 3) Depolama Erişim Çerçevesi (SAF): ACTION_OPEN_DOCUMENT_TREE ile kullanıcı tarafından seçilen dizinler için kalıcı URI izinleri (takePersistableUriPermission) verilerek, dosya yolu (path) soyutlanarak güvenli erişim sağlanır. Bu mekanizma, File API’sinin yerini ContentResolver ve DocumentFile API’lerinin almasını zorunlu kılar.
Bölüm 3: Bilim Dünyası ve Uzmanlar Nasıl İnceliyor?
Endüstriyel normlar ve uyumluluk standartları; Google Play Console politika güncellemeleri (Hedef API Seviyesi zorunluluğu), Android Uyumluluk Tanım Belgesi (CDD – Compatibility Definition Document) ve Android Güvenlik Modeli belgeleri tarafından belirlenir. Metodolojik olarak; İzin Minimizasyonu (Runtime Permission Model), Veri Yerelliği (On-device processing), ve Şeffaf Kullanıcı Onayı (User Consent) prensipleri işletilir. Ölçüm ve analizde; dumpsys package <pkg> komutları ile verilen URI izinlerinin denetlenmesi, logcat ile SecurityException stack trace’lerinin analizi ve StorageManager/MediaStore performans metrikleri (I/O gecikmesi, tarama süresi) kullanılır. Uluslararası standartlarda GDPR (Madde 25: Tasarım ve Varsayılan Gizlilik) ve CCPA uyumluluğu, Scoped Storage’ın veri işleme sınırlılığı sayesinde doğal olarak sağlanır. Sektörel en iyi uygulamalar (Best Practices); Jetpack MediaStore kütüphanesi kullanımı, PendingIntent ile medya oluşturma (createWriteRequest), ve DocumentsUI entegrasyonu için ActivityResultContracts (OpenDocumentTree) kullanımını kapsar.
Bölüm 4: Önemli Parametreler ve Karşılaştırma Rehberi
| Parametre | Olcut / Deger | Metrik | Stratejik Etki |
|---|---|---|---|
| API Seviyesi Geçiş Zorunluluğu | Android 11 (API 30) / targetSdkVersion >= 30 | %100 Uyumluluk Oranı | Play Store yayını için kritik kırılma noktası (Hard Requirement). |
| Uygulama Özel Dizin Erişimi | getExternalFilesDir(null) -> Android/data/pkg/ |
0 İzin Gerekli (Read/Write) | En yüksek performans, tam yalıtım, kaldırma temizliği. |
| Medya Dosyası Sahiplik Yazma | MediaStore.Images/Video/Audio Insert |
API 29: READ_EXTERNAL_STORAGE; API 30+: İzinsiz |
Kullanıcı galerisi entegrasyonu, meta veri koruması. |
| Başkalarının Medya Okuma | READ_MEDIA_IMAGES/VIDEO/AUDIO (API 33+) |
Çoklu İzin Grubu (Granular Permissions) | Veri sızıntısı riskini azaltır, kullanıcı şeffaflığı artar. |
| Tüm Dosya Erişimi (MANAGE_EXTERNAL_STORAGE) | ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION |
Yüksek Risk / Google Play Kısıtlamalı | Yedekleme, dosya yöneticisi, AV uygulamaları için istisnai. |
| SAF (Storage Access Framework) Kullanımı | ACTION_OPEN_DOCUMENT_TREE + takePersistableUriPermission |
Kullanıcı Etkileşimi Gerekli (One-time) | Yol (Path) bağımsızlığı, cihaz/bulut agnostik erişim. |
| Medya Tarama (MediaScanner) Gecikmesi | MediaScannerConnection.scanFile / Sistem Tarayıcısı |
Saniyeler-Dakikalar (Dosya boyutuna göre) | Kullanıcı deneyimi (UX) için asenkron işleme zorunluluğu. |
| Dosya Yolu (Path) Kullanımı | File.getAbsolutePath() / java.io.File |
Yasaklı / Çalışmaz (API 29+) | Kod tabanı refaktör zorunluluğu (ContentResolver/Uri). |
| Kaldırma Üzerine Veri Silinmesi | Android/data/pkg/ & Android/media/pkg/ |
Otomatik (System Server) | “Right to be Forgotten” / KVKK Madde 7 uyumu. |
| Yedekleme/Transfer Senaryosu | android:allowBackup / BackupAgent / SAF |
Kullanıcı Onayı + SAF Tree URI | Veri taşınabilirliği (Portability) garantisi. |
| Performans Etkisi (I/O Overhead) | ContentResolver vs File API |
%5-15 Gecikme Artışı (Küçük dosyalarda) | Büyük veri kümeleri için batch işlem / ParcelFileDescriptor önerisi. |
| Gizlilik Meta Verisi Koruması | EXIF Konum Verisi (MediaStore.Images.ImageColumns.LATITUDE) |
API 29+: Otomatik Temizleme (Force) | Konum gizliliği ihlali riskinin sistem seviyesinde önlenmesi. |
| Geçiş Bayrağı (Legacy Mode) | requestLegacyExternalStorage="true" |
Sadece API 29 (Android 10) için geçerli | API 30+ tamamen devre dışı; teknik borç (Technical Debt) yaratır. |
Bölüm 5: Günlük Hayatta ve Doğada Nerede Karşımıza Çıkar?
Saha uygulamalarında Scoped Storage, üç ana senaryoda kritik farklılaşma gösterir. Birinci Senaryo (Sosyal Medya / Kamera Uygulamaları): Uygulama çektiği fotoğrafı MediaStore.Images içine ContentValues ile IS_PENDING=1 olarak ekler, düzenleme bitince IS_PENDING=0 yapar. Bu, dosyanın galeride görünmemesini sağlar ve READ_MEDIA_IMAGES izni olmadan yazım yapar. İkinci Senaryo (Belge Yöneticisi / Yedekleme Araçları): Kullanıcı ACTION_OPEN_DOCUMENT_TREE ile “İndirilenler” veya harici SD kart kök dizinini seçer. Uygulama takePersistableUriPermission ile bu URI’yi kalıcı hale getirerek, yeniden başlatmalarda bile DocumentFile ağacı üzerinden yinelemeli (recursive) tarama ve kopyalama yapar. Üçüncü Senaryo (Oyun / Büyük Veri Setleri): OBB (Opaque Binary Blob) dosyaları veya genişletilmiş varlıklar (assets) için Android/obb/pkg/ veya Android/data/pkg/files/ kullanılır. Bu dizinler medya tarayıcısından gizlidir, performanslıdır ve uygulama silinince temizlenir. Kritik vaka analizi: FileProvider olmadan Intent.ACTION_VIEW ile dosya paylaşımı FileUriExposedException fırlatır; çözüm FileProvider.getUriForFile ile FLAG_GRANT_READ_URI_PERMISSION kullanmaktır.
Bölüm 6: Karşılaşılan Zorluklar ve Pratik Çözümler
Operasyonel darboğazlar; 1) Yol (Path) Bağımlılığı Olan Eski Kod Tabanları: C/C++ (JNI) kütüphaneleri veya üçüncü taraf SDK’lar fopen(path) bekler. Çözüm: ParcelFileDescriptor alıp pfd.getFd() ile dosya tanıtıcısını (file descriptor) native katmana geçirme veya android:requestLegacyExternalStorage (sadece API 29) ile geçici süre kazandırma. 2) Medya Tarama Gecikmesi: Büyük video dosyaları yazıldıktan hemen sonra MediaStore sorgusunda görünmez. Çözüm: MediaScannerConnection.scanFile çağrısı veya MediaStore.createWriteRequest -> PendingIntent sonrası kullanıcı onayı ile anında görünürlük. 3) MANAGE_EXTERNAL_STORAGE Reddi Riski: Google Play, bu izni sadece “Tüm Dosyaları Yönet” işlevi olan uygulamalara (dosya yöneticisi, yedekleme, virüs tarayıcı) verir. Çözüm: İzin talebinden önce Environment.isExternalStorageManager() kontrolü, reddedilirse SAF yedek mekanizması (ACTION_OPEN_DOCUMENT_TREE) sunma. 4) Taşınabilir Depolama (Adoptable Storage) Kararsızlığı: Şifreli olarak benimsenen SD kartlar cihazdan çıkarıldığında Android/data erişilemez hale gelir. Çözüm: Kritik veriler için dahili depolama (getFilesDir()) veya bulut yedekleme zorunluluğu. 5) Çoklu Kullanıcı / İş Profili (Work Profile) Yalıtımı: UserManager ve StorageManager getUuidForPath ile doğru volume UUID’sinin hedeflenmesi gerekir.
Bölüm 7: Gelecek Perspektifi ve Yeni Gelişmeler
Android 14 (API 34) ve 15 (VanillaIceCream) ekosisteminde Scoped Storage, Fotoğraf Seçici (Photo Picker) ve Video Seçici bileşenleriyle “İzinsiz Veri Erişimi” (Zero-permission access) paradigmasına evrilmiştir. MediaStore artık MediaColumns.RELATIVE_PATH ve IS_FAVORITE, IS_TRASHED sütunları ile dosya yöneticisi semantikleri kazandırmıştır. Android 15’te tanıtılan Depolama Alanı Yalıtımı (Storage Space Isolation) deneyleri, uygulamaların kendi kota alanları dışında geçici dosya bile oluşturamayacağı katı kvota (Quota) mekanizmalarını test etmektedir. Gelecek 5-10 yılık projeksiyonda; Sanal Dosya Sistemleri (Virtual File Systems – VFS) üzerinden bulut depolama (Google Drive, OneDrive) ile yerel depolamanın DocumentsProvider arayüzünde birleşmesi, Federated Learning için cihazda işlenen verinin dosya sistemi izolasyonuyla eğitim veri kümelerinden ayrıştırılması, ve Rust tabanlı sistem servisleri (rustls, binder) ile bellek güvenliği hatalarının (use-after-free, buffer overflow) depolama katmanından elimine edilmesi öngörülmektedir. Akademik konsensüs, “Dosya Sistemi” kavramının kullanıcı arayüzünden tamamen soyutlanıp “Veri Nesneleri” (Data Objects) ve “İzinli Yetenekler” (Capabilities) modeline tamamen geçeceğini işaret etmektedir.
Bölüm 8: Merak Edilen Sorular ve Cevaplar
Soru 1: Android 11+ (API 30+) hedeflerken Environment.getExternalStorageDirectory() neden null veya boş döndürüyor ve alternatif nedir?
Cevap: Bu yöntem API 29’da “deprecated”, API 30+’da ise işlevsiz hale getirilmiştir. Scoped Storage mimarisi “kök dizin” kavramını uygulamadan gizler. Alternatif olarak; uygulama özel dosyalar için context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS) (izin gerektirmez), paylaşılan medya için MediaStore koleksiyonları (MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)), kullanıcı seçili dizinler için ActivityResultContracts.OpenDocumentTree() ile elde edilen Uri ve DocumentFile API’si kullanılmalıdır.
Soru 2: MANAGE_EXTERNAL_STORAGE (Tüm Dosyaları Yönet) izni Play Store’da nasıl onaylanır ve reddedilirse ne yapmalı?
Cevap: Google Play Console’da “Uygulama İçeriği” -> “Hassas İzinler” bölümünden “Tüm Dosyaları Yönet” için bir açıklama videosu ve metin gönderilerek “Temel İşlev” (Core Functionality) kanıtı sunulur. Sadece dosya yöneticisi, yedekleme, güvenlik, belge tarayıcı kategorilerinde onay alınır. Reddedilirse (veya kullanıcı ayarlardan vermezse), uygulama Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION ile kullanıcıyı ayar sayfasına yönlendirmeli ve SAF (ACTION_OPEN_DOCUMENT_TREE) ile kısıtlı erişim yedek mekanizması (Graceful Degradation) sunmalıdır.
Soru 3: Native (C/C++ JNI) kodda fopen("/sdcard/...", "r") çalışmıyor, dosya tanıtıcısı (fd) nasıl alınır?
Cevap: Java/Kotlin tarafında ContentResolver.openFileDescriptor(uri, "r") ile ParcelFileDescriptor (PFD) alınır. pfd.getFd() bu dosya tanıtıcısını (int fd) verir. Bu fd JNI üzerinden jint olarak native kodda FileDescriptor nesnesine veya POSIX read(fd, buf, size) / write(fd, buf, size) çağrılarına doğrudan geçirilebilir. ParcelFileDescriptor.dup() ile sahiplik kopyalanabilir. Bu yöntem, dosya yolu (path) bilmeden güvenli I/O sağlar.
Soru 4: Uygulama silindiğinde Android/data/package_name/ dizini siliniyor mu, kullanıcı verilerini nasıl kalıcı tutarım?
Cevap: Evet, Android 11+ da Android/data/ ve Android/media/ dizinleri uygulama kaldırıldığında sistem tarafından otomatik ve geri alınamaz şekilde silinir. Kullanıcı verilerini (PDF, yedek, dışa aktarım) kalıcı tutmak için: 1) MediaStore.Downloads veya MediaStore.Files (API 29+) kullanarak “İndirilenler” veya “Belgeler” koleksiyonuna yazın (sahiplik uygulamada kalır ama medya tarayıcısında görünür). 2) Veya SAF ile ACTION_CREATE_DOCUMENT / ACTION_OPEN_DOCUMENT_TREE kullanarak kullanıcının seçtiği bir dizine (örn. Documents/MyAppBackups) yazın; bu dizin uygulama silinse bile kalır.
Soru 5: MediaStore ile büyük bir video dosyası yazarken IS_PENDING=1 kullanımının amacı ve yaşam döngüsü nedir?
Cevap: IS_PENDING=1 (ContentValues ile insert edilirken), dosyanın “taslak” (pending) durumda olduğunu belirtir. Bu süreçte dosya: Galeride/görünümde gözükmez, diğer uygulamalar MediaStore sorgusunda görmez, medya tarayıcısı (MediaScanner) taramaz. Uygulama veri yazmayı bitirdiğinde (örn. ParcelFileDescriptor kapatıldığında), ContentResolver.update(uri, {IS_PENDING: 0}, ...) çağrısı yapılır. Sistem dosyayı indeksler, thumbnail üretir ve galeride görünür hale getirir. Bu, yarım kalmış/bozuk dosyaların kullanıcıya sızdırılmasını engeller.
Soru 6: Scoped Storage performansını (I/O hızı) File API seviyesine nasıl çekerim?
Cevap: ContentResolver tekil işlemlerde binder IPC maliyeti nedeniyle yavaştır. Optimizasyonlar: 1) Batch İşlemler: ContentProviderOperation listesi ile applyBatch() kullanarak tek transaction’da çoklu insert/update. 2) ParcelFileDescriptor + Memory Mapping: pfd.getFileDescriptor() ile Mmap (native) veya FileChannel.map() (Java) kullanarak dosyayı belleğe eşleyin (Zero-copy read/write). 3) Executor/Thread Pool: I/O işlemlerini Dispatchers.IO (Kotlin Coroutines) veya ExecutorService ile ana iş parçacığından (Main Thread) ayırın. 4) Query Projeksiyonu: query(uri, projection, ...) ile sadece gerekli sütunları (ID, DISPLAY_NAME, SIZE, DATE_MODIFIED) çekin, * çekmeyin.
Bölüm 9: Bilmeniz Gereken Temel Terimler
Scoped Storage (Kapsamlı Depolama): Uygulamaların dış depolama alanına erişimini, kendi özel dizinleri ve kullanıcı onayıyla erişilen medya/dosya koleksiyonları ile sınırlayan, dosya yolu (path) tabanlı erişimi engelleyen Android güvenlik mimarisi (API 29+).
MediaStore (Medya Mağazası): Resim, video, ses dosyalarının meta verilerini (MIME type, tarih, konum, boyut) indekleyen, ContentProvider arayüzüyle uygulamalara sorgulama, ekleme, silme yetkisi veren sistem veritabanı servisi.
SAF (Storage Access Framework) / Depolama Erişim Çerçevesi: Uygulamaların dosya yolu bilmeden, DocumentsProvider arayüzü uygulayan herhangi bir kaynak (yerel, bulut, USB OTG) üzerinden ACTION_OPEN_DOCUMENT / ACTION_OPEN_DOCUMENT_TREE ile kullanıcı merkezli güvenli erişim sağladığı çerçeve.
ParcelFileDescriptor (PFD): Bir dosya veya dosya benzeri kaynağın (pipe, socket, memory file) çekirdek seviyesindeki dosya tanıtıcısını (file descriptor) taşıyan, işlemler arası (IPC) geçirilebilen, FileDescriptor nesnesini sarmalayan sınıf. Native kod entegrasyonu için kritiktir.
MANAGE_EXTERNAL_STORAGE (Tüm Dosyaları Yönet İzni): Android 11+ da uygulamaya, kendi sandboxı dışındaki tüm dosyalara (diğer uygulamaların verileri dahil) okuma/yazma/silme yetkisi veren, Google Play politikalarıyla sıkı denetlenen, “Yüksek Riskli” sınıflandırılan özel izin (android.permission.MANAGE_EXTERNAL_STORAGE).
ContentResolver: Uygulamanın ContentProvider veri kaynakları (MediaStore, Downloads, SAF, özel provider’lar) ile iletişim kurmasını sağlayan, CRUD (Create, Read, Update, Delete) operasyonlarını (insert, query, update, delete, openFileDescriptor) gerçekleştiren merkezi istemci nesnesi.
Bölüm 10: Özet ve Çıkarılması Gereken Dersler
Android Scoped Storage, dosya sistemi güvenliğini “uygulama merkezli”dan “veri ve kullanıcı merkezli” bir paradigmaya taşıyan, modern mobil işletim sistemleri için bir referans mimari haline gelmiştir. Analizler, geçiş sürecinin (API 29-33) teknik borç (legacy path handling, JNI fd bridging) yarattığını ancak uzun vadede veri sızıntısı vektörlerini (path traversal, metadata leakage, orphan files) sistematik olarak elimine ettiğini göstermektedir. Kurumsal karar vericiler için stratejik yol haritası şudur: 1) Hedef SDK Zorunluluğu: targetSdkVersion 34+ (Android 14) artık Play Store için şart; requestLegacyExternalStorage tamamen kaldırılmalıdır. 2) Mimari Refaktör: java.io.File ve path string bağımlılıkları Uri, ContentResolver, DocumentFile abstraksiyonlarıyla değiştirilmeli, Repository pattern ile veri kaynağı soyutlanmalıdır. 3) İzin Stratejisi: MANAGE_EXTERNAL_STORAGE yerine Photo Picker / MediaStore / SAF üçlüsünü benimseyerek “İzinsiz En İyi Deneyim” (Zero-permission Best UX) hedeflenmelidir. 4) Test ve Doğrulama: Scoped Storage davranışları emülatörde değil, Farklı OEM’ler (Samsung, Xiaomi, Pixel) ve Farklı API Seviyeleri (30, 31, 33, 34) üzerinde StorageManager davranış testleri (CTS/VTS) ile doğrulanmalıdır. Bu mimari, KVKK/GDPR uyumluluğunu mühendislik seviyesinde garanti altına alarak, ekosistemin “Gizlilik Öncelikli” (Privacy-First) geleceğinin temel taşıdır.