author | Tellen Yu <tellen.yu@amlogic.com> | 2017-10-30 06:28:18 (GMT) |
---|---|---|
committer | Gerrit Code Review <gituser@scgit.amlogic.com> | 2017-10-30 06:28:18 (GMT) |
commit | 9619e7c53e6837decea8002caf01c59710709dad (patch) | |
tree | c0254a102378d88b6726accebbfdf7b23f1fd6f8 | |
parent | 22517dfe2841decac94db7b389117bbae79c886a (diff) | |
parent | 7066f3fc8ad66402d7695fbff027b921a7dd6892 (diff) | |
download | frameworks-9619e7c53e6837decea8002caf01c59710709dad.zip frameworks-9619e7c53e6837decea8002caf01c59710709dad.tar.gz frameworks-9619e7c53e6837decea8002caf01c59710709dad.tar.bz2 |
Merge "FileListManager: add FileListManager & droidvold: add droidmount binder service[4/5]" into o-amlogic
-rw-r--r-- | core/java/com/droidlogic/app/FileListManager.java | 535 | ||||
-rw-r--r-- | core/java/com/droidlogic/app/IDroidVoldManager.java | 402 | ||||
-rw-r--r-- | core/res/src/com/droidlogic/DroidVoldManager.java | 310 |
3 files changed, 1246 insertions, 1 deletions
diff --git a/core/java/com/droidlogic/app/FileListManager.java b/core/java/com/droidlogic/app/FileListManager.java new file mode 100644 index 0000000..bb95408 --- a/dev/null +++ b/core/java/com/droidlogic/app/FileListManager.java @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * @author XiaoLiang.Wang + * @version 1.0 + * @date 2017/09/20 + * @par function description: + * - 1 get amlogic volume files list + */ + +package com.droidlogic.app; + +import android.content.Context; +import android.util.Log; +import android.os.Environment; +import android.os.ServiceManager; +import android.os.SystemProperties; +import android.os.storage.StorageManager; +import android.os.storage.DiskInfo; +import android.os.storage.VolumeInfo; + +import java.io.File; +import java.io.FileFilter; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.lang.String; + +import com.droidlogic.app.SystemControlManager; +import com.droidlogic.app.IDroidVoldManager; + +public class FileListManager { + private String TAG = "FileListManager"; + private boolean mDebug = false; + private Context mContext; + + private StorageManager mStorageManager; + private static SystemControlManager mSystemControl; + private IDroidVoldManager mDroidVoldManager; + + public static final String STORAGE = "/storage"; + public static final String MEDIA_RW = "/mnt/media_rw"; + public static final String NAND = Environment.getExternalStorageDirectory().getPath();//storage/emulated/0 + + private static String ISOpath = null; + private static final String iso_mount_dir_s = "/mnt/loop"; + + private List<Map<String, Object>> mListDev = new ArrayList<Map<String, Object>>(); + private List<Map<String, Object>> mListFile = new ArrayList<Map<String, Object>>(); + private List<Map<String, Object>> mListDir = new ArrayList<Map<String, Object>>(); + private Map<String, Object> mMap; + //key for map + public static final String KEY_NAME = "key_name"; + public static final String KEY_PATH = "key_path"; + public static final String KEY_TYPE = "key_type"; + public static final String KEY_DATE = "key_date"; + public static final String KEY_SIZE = "key_size"; + public static final String KEY_SELE = "key_sele"; + public static final String KEY_RDWR = "key_rdwr"; + + //type for storage + public static final String TYPE_NAND = "type_nand"; + public static final String TYPE_UDISK = "type_udisk"; + public static final String TYPE_SDCARD = "type_sdcard"; + + //selected flag + public static final String SELE_NO = "sele_no"; + public static final String SELE_YES = "sele_yes"; + + /* file type extensions */ + //video + private static final String video_extensions = "3gp,asf,avi,dat,divx,f4v,flv,h264,iso,lst,m2ts,m4v,mkv,mp2,mp4,mov,mpe,mpeg,mpg,mts,rm,rmvb,ts,tp,mvc,vc1,vob,wm,wmv,webm,m2v,pmp,bit,h265,3g2,mlv,hm10,ogm,vp9,trp,bin,ivf"; + + //music + private static final String[] music_extensions = { + ".mp3", ".wma", ".m4a", ".aac", ".ape", ".mp2", ".ogg", ".flac", ".alac", ".wav", + ".mid", ".xmf", ".mka", ".aiff", ".aifc", ".aif", ".pcm", ".adpcm" + }; + + //photo + private static final String[] photo_extensions = { + ".jpg", ".jpeg", ".bmp", ".tif", ".tiff", ".png", ".gif", ".giff", ".jfi", ".jpe", ".jif", + ".jfif", ".mpo", ".webp", ".3dg", "3dp" + }; + + private static final String[] plain_extensions = {".txt",".c",".cpp",".java",",conf",".h", + ".log",".rc" + }; + + public FileListManager(Context context) { + mContext = context; + mDebug = false; + mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE); + mSystemControl = new SystemControlManager(context); + mDroidVoldManager = IDroidVoldManager.Stub.asInterface(ServiceManager.getService("droidmount")); + + checkDebug(); + } + + private void checkDebug() { + if (SystemProperties.getBoolean("sys.filelistanager.debug", false)) { + mDebug = true; + } + } + + public static boolean isVideo(String filename) { + String name = filename.toLowerCase(); + String videos[] = video_extensions.split(","); + for (String ext : videos) { + if (name.endsWith(ext)) + return true; + } + return false; + } + + public static boolean isMusic(String filename) { + String name = filename.toLowerCase(); + for (String ext : music_extensions) { + if (name.endsWith(ext)) + return true; + } + return false; + } + + public static boolean isPhoto(String filename) { + String name = filename.toLowerCase(); + for (String ext : photo_extensions) { + if (name.endsWith(ext)) + return true; + } + return false; + } + + public static boolean isApk(String filename) { + String name = filename.toLowerCase(); + if (name.endsWith(".apk")) + return true; + return false; + } + + public static boolean isHtm(String filename) { + String name = filename.toLowerCase(); + if (name.endsWith(".htm") || name.endsWith(".shtml") || name.endsWith(".bin")) + return true; + return false; + } + + public static boolean isPdf(String filename) { + String name = filename.toLowerCase(); + if (name.endsWith(".pdf")) + return true; + return false; + } + + public static boolean isPlain(String filename) { + String name = filename.toLowerCase(); + for (String ext : plain_extensions) { + if (name.endsWith(ext)) + return true; + } + return false; + } + + private static void mount(String path) { + mSystemControl.loopMountUnmount(false, null); + mSystemControl.loopMountUnmount(true, path); + } + + public static boolean isISOFile (File file) { + String fname = file.getName(); + String sname = ".iso"; + if (fname == "") { + return false; + } + if (file.isFile() && fname.toLowerCase().endsWith (sname)) { + return true; + } + return false; + } + + private static boolean isHasDir(File[] files, String name) { + for (File file : files) { + if (name != null && name.equals(file.getName()) && file.isDirectory()) + return true; + } + return false; + } + + public static boolean isBDFile(File file) { + if (file.isDirectory()) { + File[] rootFiles = file.listFiles(); + if (rootFiles != null && rootFiles.length >= 1 && isHasDir(rootFiles, "BDMV")) { + File bdDir = new File(file.getPath(), "BDMV"); + String[] files = bdDir.list(); + ArrayList<String> names = new ArrayList<String>(); + for (int i = 0; i < files.length; i++) + names.add(files[i]); + if (names.contains("index.bdmv") && names.contains("PLAYLIST") + && names.contains("CLIPINF") && names.contains("STREAM")) + return true; + } + } else if (isISOFile(file)) { + ISOpath = file.getPath(); + mount(ISOpath); + File isofile = new File(iso_mount_dir_s); + if (isofile.exists() && isofile.isDirectory()) { + File[] rootFiles = isofile.listFiles(); + if (rootFiles != null && rootFiles.length >= 1 && isHasDir(rootFiles, "BDMV")) { + File bdfiles = new File(iso_mount_dir_s, "BDMV"); + String[] bdmvFiles = bdfiles.list(); + ArrayList<String> names = new ArrayList<String>(); + for (int i = 0; i < bdmvFiles.length; i++) + names.add(bdmvFiles[i]); + if (names.contains("index.bdmv") && names.contains("PLAYLIST") + && names.contains("CLIPINF") && names.contains("STREAM")) { + return true; + } + } + } + } + return false; + } + + public static String CheckMediaType(File file){ + String typeStr="application/*"; + String filename = file.getName(); + + if (isVideo(filename)) + typeStr = "video/*"; + else if (isMusic(filename)) + typeStr = "audio/*"; + else if (isPhoto(filename)) + typeStr = "image/*"; + else if (isApk(filename)) + typeStr = "application/vnd.android.package-archive"; + else if (isHtm(filename)) + typeStr = "text/html"; + else if (isPdf(filename)) + typeStr = "application/pdf"; + else if (isPlain(filename)) + typeStr = "text/plain"; + else { + typeStr = "application/*"; + } + return typeStr; + } + + public class MyFilter implements FileFilter { + private String extensions; + public MyFilter (String extensions) { + this.extensions = extensions; + } + public boolean accept (File file) { + StringTokenizer st = new StringTokenizer (this.extensions, ","); + if (file.isDirectory()) { + return true; + } + String name = file.getName(); + if (st.countTokens() == 1) { + String str = st.nextToken(); + String filenamelowercase = name.toLowerCase(); + return filenamelowercase.endsWith (str); + } else { + int index = name.lastIndexOf ("."); + if (index == -1) { + return false; + } + else if (index == (name.length() - 1)) { + return false; + } + else { + //for(int i = 0; i<st.countTokens(); i++) + while (st.hasMoreElements()) { + String extension = st.nextToken(); + if (extension.equals (name.substring (index + 1).toLowerCase())) { + return true; + } + } + return false; + } + } + } + } + + public List<Map<String, Object>> getDevices() { + Map<String, Object> map; + //local disk (nand) + mListDev.clear(); + File file = new File(NAND); + if (file != null && file.exists() && file.isDirectory() && file.listFiles() != null && file.listFiles().length > 0) { + map = new HashMap<String, Object>(); + map.put(KEY_NAME, "Local Disk"); + map.put(KEY_PATH, NAND); + map.put(KEY_DATE, 0); + map.put(KEY_SIZE, 1); + map.put(KEY_SELE, SELE_NO); + map.put(KEY_TYPE, TYPE_NAND); + map.put(KEY_RDWR, null); + + if (mDebug) { + Log.i(TAG, "[getDevices]nand path:" + NAND); + } + mListDev.add(map); + } + + //external storage + Class<?> volumeInfoClazz = null; + Method getDescriptionComparator = null; + Method getBestVolumeDescription = null; + Method getVolumes = null; + Method isMountedReadable = null; + Method getType = null; + Method getPath = null; + Method getDisk = null; + List<?> volumes = null; + try { + volumeInfoClazz = Class.forName("android.os.storage.VolumeInfo"); + getDescriptionComparator = volumeInfoClazz.getMethod("getDescriptionComparator"); + getBestVolumeDescription = StorageManager.class.getMethod("getBestVolumeDescription", volumeInfoClazz); + getVolumes = StorageManager.class.getMethod("getVolumes"); + isMountedReadable = volumeInfoClazz.getMethod("isMountedReadable"); + getType = volumeInfoClazz.getMethod("getType"); + getPath = volumeInfoClazz.getMethod("getPath"); + getDisk = volumeInfoClazz.getMethod("getDisk"); + volumes = (List<?>)getVolumes.invoke(mStorageManager); + //Collections.sort(volumes, getDescriptionComparator.invoke()); + + for (Object vol : volumes) { + if (vol != null && (boolean)isMountedReadable.invoke(vol) && (int)getType.invoke(vol) == 0) { + File pathFile = (File)getPath.invoke(vol); + String path = pathFile.getAbsolutePath(); + String name = (String)getBestVolumeDescription.invoke(mStorageManager, vol); + + map = new HashMap<String, Object>(); + map.put(KEY_NAME, name); + map.put(KEY_PATH, path); + map.put(KEY_DATE, 0); + map.put(KEY_SIZE, 1); + map.put(KEY_SELE, SELE_NO); + map.put(KEY_RDWR, null); + DiskInfo disk = (DiskInfo)getDisk.invoke(vol); + if (disk.isUsb()) { + map.put(KEY_TYPE, TYPE_UDISK); + } + else { + map.put(KEY_TYPE, TYPE_SDCARD); + } + + if (mDebug) { + Log.i(TAG, "[getDevices]volume path:" + path); + } + mListDev.add(map); + } + } + } catch (Exception ex) { + Log.e(TAG, "[getDevices]Exception ex:" + ex); + ex.printStackTrace(); + } + + //check storage + file = new File(STORAGE); + if (file != null && file.exists() && file.isDirectory()) { + // TODO: needn't check right now + } + + //check /mnt/media_rw/ + file = new File(MEDIA_RW); + if (file != null && file.exists() && file.isDirectory()) { + Map<String, Object> maptmp; + boolean skipFlag = false; + + for (File filetmp : file.listFiles()) { + skipFlag = false; + String path = filetmp.getAbsolutePath(); + String name = filetmp.getName(); + if (mDebug) { + Log.i(TAG, "[getDevices]name:" + name + ", path:" + path); + } + if (mListDev != null && !mListDev.isEmpty()) { + for (int i = 0; i < mListDev.size(); i++) { + //get uuid to compare with list files' name + String uuid = null; + maptmp = mListDev.get(i); + if (maptmp != null) { + String pathtmp = (String) maptmp.get(KEY_PATH); + if (pathtmp != null) { + int idx = pathtmp.lastIndexOf("/"); + if (idx >= 0) { + uuid = pathtmp.substring(idx + 1); + } + } + } + + if (mDebug) { + Log.i(TAG, "[getDevices]uuid:" + uuid); + } + if (uuid != null && uuid.equals(name)) { + skipFlag = true; + break; + } + } + } + + if (!skipFlag) { + skipFlag = true;//reset skip flag + map = new HashMap<String, Object>(); + map.put(KEY_NAME, name); + map.put(KEY_PATH, path); + map.put(KEY_DATE, 0); + map.put(KEY_SIZE, 1); + map.put(KEY_SELE, SELE_NO); + map.put(KEY_RDWR, null); + int diskFlag = 0; + try { + diskFlag = mDroidVoldManager.getVolumeInfoDiskFlags(path); + } catch (Exception e) { + Log.e(TAG, "[getDevices]Exception e:" + e); + e.printStackTrace(); + } + Log.i(TAG, "getDevices() diskFlag:" + diskFlag); + if (diskFlag == 8) { + map.put(KEY_TYPE, TYPE_UDISK); + } + else if (diskFlag == 4){ + map.put(KEY_TYPE, TYPE_SDCARD); + } + if (mDebug) { + Log.i(TAG, "[getDevices]/mnt/media_rw path:" + path); + } + mListDev.add(map); + } + } + } + + if (mDebug) { + Log.i(TAG, "[getDevices]====start print list=========================="); + if (mListDev != null && !mListDev.isEmpty()) { + Map<String, Object> maptmp; + int listSize = mListDev.size(); + for (int i = 0; i < listSize; i++) { + maptmp = mListDev.get(i); + if (maptmp != null) { + String nametmp = (String) maptmp.get(KEY_NAME); + String pathtmp = (String) maptmp.get(KEY_PATH); + } + } + } + Log.i(TAG, "[getDevices]====end print list=========================="); + } + + return mListDev; + } + + public List<Map<String, Object>> getDirs(String directory, String strs) { + Map<String, Object> map; + String extensions = video_extensions; + mListDir.clear(); + File pfile = new File(directory); + File[] files = null; + if (strs.indexOf(".") == 0) { + files = pfile.listFiles(new MyFilter(strs)); + } else if (strs.equals("video")) { + files = pfile.listFiles(new MyFilter(extensions)); + } + if (files != null && (files.length > 0)) { + for (int i = 0; i < files.length; i++) { + String pathtmp = files[i].getAbsolutePath(); + String nametmp = files[i].getName(); + String str = null; + File tempF = files[i]; + str = files[i].toString(); + map = new HashMap<String, Object>(); + map.put(KEY_NAME, nametmp); + map.put(KEY_PATH, pathtmp); + map.put(KEY_DATE, 0); + map.put(KEY_SIZE, 1); + map.put(KEY_SELE, SELE_NO); + map.put(KEY_RDWR, null); + map.put(KEY_TYPE, null); + if (mDebug) { + Log.i(TAG, "[getDirs]volume pathtmp:" + pathtmp); + } + if (strs == ".apk") { + mListDir.add(map); + } else if (strs == "video" && (isBDFile(tempF) || (tempF.isFile() && !isISOFile(tempF)))) { + mListDir.add(map); + } else if (strs == "video") { + mListDir.add(map); + } + } + } + return mListDir; + } + + public List<Map<String, Object>> getFiles(String path) { + Map<String, Object> map; + mListFile.clear(); + File file = new File(path); + if (file != null && file.exists() && file.isDirectory()) { + for (File filetmp : file.listFiles()) { + String pathtmp = filetmp.getAbsolutePath(); + String nametmp = filetmp.getName(); + map = new HashMap<String, Object>(); + map.put(KEY_NAME, nametmp); + map.put(KEY_PATH, pathtmp); + map.put(KEY_DATE, 0); + map.put(KEY_SIZE, 1); + map.put(KEY_SELE, SELE_NO); + map.put(KEY_RDWR, null); + map.put(KEY_TYPE, null); + if (mDebug) { + Log.i(TAG, "[getFiles]volume pathtmp:" + pathtmp); + } + mListFile.add(map); + } + } + return mListFile; + } +}
\ No newline at end of file diff --git a/core/java/com/droidlogic/app/IDroidVoldManager.java b/core/java/com/droidlogic/app/IDroidVoldManager.java new file mode 100644 index 0000000..c98d8a9 --- a/dev/null +++ b/core/java/com/droidlogic/app/IDroidVoldManager.java @@ -0,0 +1,402 @@ +package com.droidlogic.app; + +public interface IDroidVoldManager extends android.os.IInterface { + /** Local-side IPC implementation stub class. */ + public static abstract class Stub extends android.os.Binder implements com.droidlogic.app.IDroidVoldManager { + private static final java.lang.String DESCRIPTOR = "com.droidlogic.app.IDroidVoldManager"; + + /** Construct the stub at attach it to the interface. */ + public Stub() { + this.attachInterface(this, DESCRIPTOR); + } + + /** + * Cast an IBinder object into an com.droidlogic.app.IDroidVoldManager interface, + * generating a proxy if needed. + */ + + public static com.droidlogic.app.IDroidVoldManager asInterface(android.os.IBinder obj) { + if ((obj == null)) { + return null; + } + + android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (((iin != null) && (iin instanceof com.droidlogic.app.IDroidVoldManager))) { + return ((com.droidlogic.app.IDroidVoldManager)iin); + } + return new com.droidlogic.app.IDroidVoldManager.Stub.Proxy(obj); + } + + @Override + public android.os.IBinder asBinder() { + return this; + } + + @Override + public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) + throws android.os.RemoteException { + switch (code) { + case INTERFACE_TRANSACTION: { + reply.writeString(DESCRIPTOR); + return true; + } + + case TRANSACTION_formatVolume: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + + int _result = this.formatVolume(_arg0); + reply.writeNoException(); + reply.writeInt(_result); + return true; + } + + case TRANSACTION_shutdown: { + data.enforceInterface(DESCRIPTOR); + android.os.storage.IStorageShutdownObserver _arg0; + _arg0 = android.os.storage.IStorageShutdownObserver.Stub.asInterface(data.readStrongBinder()); + this.shutdown(_arg0); + reply.writeNoException(); + return true; + } + + case TRANSACTION_getVolumeList: { + data.enforceInterface(DESCRIPTOR); + int _arg0; + _arg0 = data.readInt(); + java.lang.String _arg1; + _arg1 = data.readString(); + int _arg2; + _arg2 = data.readInt(); + android.os.storage.StorageVolume[] _result = this.getVolumeList(_arg0, _arg1, _arg2); + reply.writeNoException(); + reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + return true; + } + + case TRANSACTION_mkdirs: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + java.lang.String _arg1; + _arg1 = data.readString(); + int _result = this.mkdirs(_arg0, _arg1); + reply.writeNoException(); + reply.writeInt(_result); + return true; + } + + case TRANSACTION_getDisks: { + data.enforceInterface(DESCRIPTOR); + android.os.storage.DiskInfo[] _result = this.getDisks(); + reply.writeNoException(); + reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + return true; + } + + + case TRANSACTION_getVolumes: { + data.enforceInterface(DESCRIPTOR); + int _arg0; + _arg0 = data.readInt(); + android.os.storage.VolumeInfo[] _result = this.getVolumes(_arg0); + reply.writeNoException(); + reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + return true; + } + + + case TRANSACTION_getVolumeRecords: { + data.enforceInterface(DESCRIPTOR); + int _arg0; + _arg0 = data.readInt(); + android.os.storage.VolumeRecord[] _result = this.getVolumeRecords(_arg0); + reply.writeNoException(); + reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + return true; + } + + case TRANSACTION_mount: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + this.mount(_arg0); + reply.writeNoException(); + return true; + } + + case TRANSACTION_unmount: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + this.unmount(_arg0); + reply.writeNoException(); + return true; + } + + case TRANSACTION_format: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + this.format(_arg0); + reply.writeNoException(); + return true; + } + + case TRANSACTION_getVolumeInfoDiskFlags: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + int _result = this.getVolumeInfoDiskFlags(_arg0); + reply.writeNoException(); + reply.writeInt(_result); + return true; + } + } + + return super.onTransact(code, data, reply, flags); + } + + private static class Proxy implements com.droidlogic.app.IDroidVoldManager { + private android.os.IBinder mRemote; + + Proxy(android.os.IBinder remote) { + mRemote = remote; + } + + @Override + public android.os.IBinder asBinder() { + return mRemote; + } + + public java.lang.String getInterfaceDescriptor() { + return DESCRIPTOR; + } + + @Override + public int formatVolume(java.lang.String mountPoint) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + int _result; + + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(mountPoint); + mRemote.transact(Stub.TRANSACTION_formatVolume, _data, _reply, 0); + _reply.readException(); + _result = _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + @Override + public void shutdown(android.os.storage.IStorageShutdownObserver observer) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeStrongBinder((((observer!=null))?(observer.asBinder()):(null))); + mRemote.transact(Stub.TRANSACTION_shutdown, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + + @Override + public android.os.storage.StorageVolume[] getVolumeList(int uid, java.lang.String packageName, int flags) + throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + android.os.storage.StorageVolume[] _result; + + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(uid); + _data.writeString(packageName); + _data.writeInt(flags); + mRemote.transact(Stub.TRANSACTION_getVolumeList, _data, _reply, 0); + _reply.readException(); + _result = _reply.createTypedArray(android.os.storage.StorageVolume.CREATOR); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + @Override + public int mkdirs(java.lang.String callingPkg, java.lang.String path) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + int _result; + + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(callingPkg); + _data.writeString(path); + mRemote.transact(Stub.TRANSACTION_mkdirs, _data, _reply, 0); + _reply.readException(); + _result = _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + @Override + public android.os.storage.DiskInfo[] getDisks() throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + android.os.storage.DiskInfo[] _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_getDisks, _data, _reply, 0); + _reply.readException(); + _result = _reply.createTypedArray(android.os.storage.DiskInfo.CREATOR); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + @Override + public android.os.storage.VolumeInfo[] getVolumes(int flags) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + android.os.storage.VolumeInfo[] _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(flags); + mRemote.transact(Stub.TRANSACTION_getVolumes, _data, _reply, 0); + _reply.readException(); + _result = _reply.createTypedArray(android.os.storage.VolumeInfo.CREATOR); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + @Override + public android.os.storage.VolumeRecord[] getVolumeRecords(int flags) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + android.os.storage.VolumeRecord[] _result; + + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeInt(flags); + mRemote.transact(Stub.TRANSACTION_getVolumeRecords, _data, _reply, 0); + _reply.readException(); + _result = _reply.createTypedArray(android.os.storage.VolumeRecord.CREATOR); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + @Override + public void mount(java.lang.String volId) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(volId); + mRemote.transact(Stub.TRANSACTION_mount, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override + public void unmount(java.lang.String volId) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(volId); + mRemote.transact(Stub.TRANSACTION_unmount, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + + @Override + public void format(java.lang.String volId) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(volId); + mRemote.transact(Stub.TRANSACTION_format, _data, _reply, 0); + _reply.readException(); + } finally { + _reply.recycle(); + _data.recycle(); + } + } + @Override public int getVolumeInfoDiskFlags(java.lang.String mountPoint) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + int _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(mountPoint); + mRemote.transact(Stub.TRANSACTION_getVolumeInfoDiskFlags, _data, _reply, 0); + _reply.readException(); + _result = _reply.readInt(); + } + finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + } + + static final int TRANSACTION_formatVolume = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); + static final int TRANSACTION_shutdown = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); + static final int TRANSACTION_getVolumeList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); + static final int TRANSACTION_mkdirs = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); + static final int TRANSACTION_getDisks = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); + static final int TRANSACTION_getVolumes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); + static final int TRANSACTION_getVolumeRecords = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); + static final int TRANSACTION_mount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); + static final int TRANSACTION_unmount = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); + static final int TRANSACTION_format = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9); + static final int TRANSACTION_getVolumeInfoDiskFlags = (android.os.IBinder.FIRST_CALL_TRANSACTION + 10); + } + + public int formatVolume(java.lang.String mountPoint) throws android.os.RemoteException; + public void shutdown(android.os.storage.IStorageShutdownObserver observer) throws android.os.RemoteException; + public android.os.storage.StorageVolume[] getVolumeList(int uid, java.lang.String packageName, int flags) throws android.os.RemoteException; + public int mkdirs(java.lang.String callingPkg, java.lang.String path) throws android.os.RemoteException; + public android.os.storage.DiskInfo[] getDisks() throws android.os.RemoteException; + public android.os.storage.VolumeInfo[] getVolumes(int flags) throws android.os.RemoteException; + public android.os.storage.VolumeRecord[] getVolumeRecords(int flags) throws android.os.RemoteException; + public void mount(java.lang.String volId) throws android.os.RemoteException; + public void unmount(java.lang.String volId) throws android.os.RemoteException; + public void format(java.lang.String volId) throws android.os.RemoteException; + public int getVolumeInfoDiskFlags(java.lang.String mountPoint) throws android.os.RemoteException; +} diff --git a/core/res/src/com/droidlogic/DroidVoldManager.java b/core/res/src/com/droidlogic/DroidVoldManager.java index 018901d..9463838 100644 --- a/core/res/src/com/droidlogic/DroidVoldManager.java +++ b/core/res/src/com/droidlogic/DroidVoldManager.java @@ -45,11 +45,13 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.DiskInfo; import android.os.storage.IStorageShutdownObserver; import android.os.storage.StorageResultCode; +import android.os.storage.StorageManager; import android.os.storage.StorageVolume; import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; @@ -76,6 +78,13 @@ import com.android.internal.widget.LockPatternUtils; import libcore.io.IoUtils; import libcore.util.EmptyArray; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -95,11 +104,14 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import com.droidlogic.app.IDroidVoldManager; + /** * Service responsible for various storage media. Connects to {@code droidvold} to * watch for and manage dynamically added storage, such as SD cards and USB mass storage. */ -class DroidVoldManager implements INativeDaemonConnectorCallbacks { +class DroidVoldManager extends IDroidVoldManager.Stub + implements INativeDaemonConnectorCallbacks { // Static direct instance pointer for the tightly-coupled idle service to use static DroidVoldManager sSelf = null; @@ -629,17 +641,313 @@ class DroidVoldManager implements INativeDaemonConnectorCallbacks { mConnectorThread = new Thread(mConnector, VOLD_TAG); Slog.d(TAG, "start nativeNaemon"); mConnectorThread.start(); + ServiceManager.addService("droidmount", sSelf, false); + } + private String findVolumeIdForPathOrThrow(String path) { + synchronized (mLock) { + for (int i = 0; i < mVolumes.size(); i++) { + final VolumeInfo vol = mVolumes.valueAt(i); + if (vol.path != null && path.startsWith(vol.path)) { + return vol.id; + } + } + } + throw new IllegalArgumentException("No volume found for path " + path); + } + + private VolumeInfo findVolumeByIdOrThrow(String id) { + synchronized (mLock) { + final VolumeInfo vol = mVolumes.get(id); + if (vol != null) { + return vol; + } + } + throw new IllegalArgumentException("No volume found for ID " + id); } /** * Exposed API calls below here */ + @Override public void shutdown(final IStorageShutdownObserver observer) { enforcePermission(android.Manifest.permission.SHUTDOWN); Slog.i(TAG, "Shutting down"); mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget(); } + + @Override + public int formatVolume(String path) { + format(findVolumeIdForPathOrThrow(path)); + return 0; + } + + @Override + public int mkdirs(String callingPkg, String appPath) { + final int userId = UserHandle.getUserId(Binder.getCallingUid()); + final UserEnvironment userEnv = new UserEnvironment(userId); + + File appFile = null; + try { + appFile = new File(appPath).getCanonicalFile(); + } catch (IOException e) { + Slog.e(TAG, "Failed to resolve " + appPath + ": " + e); + return -1; + } + + // Try translating the app path into a vold path, but require that it + // belong to the calling package. + if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) || + FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) || + FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) { + appPath = appFile.getAbsolutePath(); + if (!appPath.endsWith("/")) { + appPath = appPath + "/"; + } + + try { + mConnector.execute("volume", "mkdirs", appPath); + return 0; + } catch (NativeDaemonConnectorException e) { + return e.getCode(); + } + } + + throw new SecurityException("Invalid mkdirs path: " + appFile); + } + + @Override + public StorageVolume[] getVolumeList(int uid, String packageName, int flags) { + final int userId = UserHandle.getUserId(uid); + + final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0; + final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0; + final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0; + + + boolean foundPrimary = false; + + final ArrayList<StorageVolume> res = new ArrayList<>(); + synchronized (mLock) { + for (int i = 0; i < mVolumes.size(); i++) { + final VolumeInfo vol = mVolumes.valueAt(i); + switch (vol.getType()) { + case VolumeInfo.TYPE_PUBLIC: + case VolumeInfo.TYPE_EMULATED: + break; + default: + continue; + } + + boolean match = false; + if (forWrite) { + match = vol.isVisibleForWrite(userId); + } else { + match = vol.isVisibleForRead(userId) + || (includeInvisible && vol.getPath() != null); + } + if (!match) continue; + + boolean reportUnmounted = false; + if ((vol.getType() == VolumeInfo.TYPE_EMULATED)) { + reportUnmounted = true; + } else if (!realState) { + reportUnmounted = true; + } + + final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, + reportUnmounted); + if (vol.isPrimary()) { + res.add(0, userVol); + foundPrimary = true; + } else { + res.add(userVol); + } + } + } + + if (!foundPrimary) { + Log.w(TAG, "No primary storage defined yet; hacking together a stub"); + + final boolean primaryPhysical = SystemProperties.getBoolean( + StorageManager.PROP_PRIMARY_PHYSICAL, false); + + final String id = "stub_primary"; + final File path = Environment.getLegacyExternalStorageDirectory(); + final String description = mContext.getString(android.R.string.unknownName); + final boolean primary = true; + final boolean removable = primaryPhysical; + final boolean emulated = !primaryPhysical; + final long mtpReserveSize = 0L; + final boolean allowMassStorage = false; + final long maxFileSize = 0L; + final UserHandle owner = new UserHandle(userId); + final String uuid = null; + final String state = Environment.MEDIA_REMOVED; + + res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path, + description, primary, removable, emulated, mtpReserveSize, + allowMassStorage, maxFileSize, owner, uuid, state)); + } + + return res.toArray(new StorageVolume[res.size()]); + } + + @Override + public DiskInfo[] getDisks() { + synchronized (mLock) { + final DiskInfo[] res = new DiskInfo[mDisks.size()]; + for (int i = 0; i < mDisks.size(); i++) { + res[i] = mDisks.valueAt(i); + } + return res; + } + } + + @Override + public VolumeInfo[] getVolumes(int flags) { + synchronized (mLock) { + final VolumeInfo[] res = new VolumeInfo[mVolumes.size()]; + for (int i = 0; i < mVolumes.size(); i++) { + res[i] = mVolumes.valueAt(i); + } + return res; + } + } + + @Override + public VolumeRecord[] getVolumeRecords(int flags) { + synchronized (mLock) { + final VolumeRecord[] res = new VolumeRecord[mRecords.size()]; + for (int i = 0; i < mRecords.size(); i++) { + res[i] = mRecords.valueAt(i); + } + return res; + } + } + + @Override + public void mount(String volId) { + enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + waitForReady(); + + final VolumeInfo vol = findVolumeByIdOrThrow(volId); + if (isMountDisallowed(vol)) { + throw new SecurityException("Mounting " + volId + " restricted by policy"); + } + try { + mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void unmount(String volId) { + enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + waitForReady(); + + final VolumeInfo vol = findVolumeByIdOrThrow(volId); + + try { + mConnector.execute("volume", "unmount", vol.id); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public void format(String volId) { + enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); + waitForReady(); + + final VolumeInfo vol = findVolumeByIdOrThrow(volId); + try { + mConnector.execute("volume", "format", vol.id, "auto"); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); + } + } + + @Override + public int getVolumeInfoDiskFlags(String mountPoint) { + int flag = 0; + int FLAG_SD = 1 << 2; + int FLAG_USB = 1 << 3; + + synchronized (mLock) { + for (int i = 0; i < mVolumes.size(); i++) { + final VolumeInfo vol = mVolumes.valueAt(i); + if (vol.path != null && mountPoint.startsWith(vol.path)) { + if (vol.getDisk().isSd()) + flag |= FLAG_SD; + else if (vol.getDisk().isUsb()) + flag |= FLAG_USB; + break; + } + } + } + + return flag; + } + + + @Override + protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return; + + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160); + synchronized (mLock) { + pw.println("Disks:"); + pw.increaseIndent(); + for (int i = 0; i < mDisks.size(); i++) { + final DiskInfo disk = mDisks.valueAt(i); + disk.dump(pw); + } + pw.decreaseIndent(); + + pw.println(); + pw.println("Volumes:"); + pw.increaseIndent(); + for (int i = 0; i < mVolumes.size(); i++) { + final VolumeInfo vol = mVolumes.valueAt(i); + if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue; + vol.dump(pw); + } + pw.decreaseIndent(); + + pw.println(); + pw.println("Records:"); + pw.increaseIndent(); + for (int i = 0; i < mRecords.size(); i++) { + final VolumeRecord note = mRecords.valueAt(i); + note.dump(pw); + } + pw.decreaseIndent(); + + final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize(); + if (pair == null) { + pw.println("Internal storage total size: N/A"); + } else { + pw.print("Internal storage ("); + pw.print(pair.first); + pw.print(") total size: "); + pw.print(pair.second); + pw.print(" ("); + pw.print((float) pair.second / TrafficStats.GB_IN_BYTES); + pw.println(" GB)"); + } + pw.println(); + pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers)); + } + + + pw.println(); + pw.println("mConnector:"); + pw.increaseIndent(); + mConnector.dump(fd, pw, args); + pw.decreaseIndent(); + } } |