1.用户需求
android R 预制文件到App的外部私有目录(Android/data/xx------>xx指应用的包名);
1.App的外部私有目录普通应用是没有权限创建的,只能使用自己应用的私有目录,首先尝试一下在系统应用(看看是否有权限)里面直接进行copy;
public boolean copy() {
final String FROMPATH = "xxxx";
final String TOPATH = "/mnt/sdcard/Android/data/xxx/xxx/xxx/xxx";
String[] dirname = null;
String[] filename =null;
File file = new File(FROMPATH);
if (file.exists()) {
filename = file.list();
Log.d(TAG, "filename.length = " + filename.length);
}
File filestore = new File(TOPATH);
if (!filestore.exists()) {
filestore.mkdir();
}
for (int k = 0; k < filename.length; k++) {
Log.d(TAG, "the filename is " + filename[k]);
InputStream fosfrom = null;
OutputStream fosto = null;
try {
fosfrom = new FileInputStream(FROMPATH + "/" + filename[k]);
fosto = new FileOutputStream(TOPATH + "/" + filename[k]);
byte[] bt = new byte[1024];
int c;
while ((c = fosfrom.read(bt)) > 0) {
fosto.write(bt, 0, c);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (fosfrom!=null) {
fosfrom.close();
}
if (fosto!=null) {
fosto.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if(k == filename.length - 1){
copyDone = true;
Log.d(TAG, "copyDone value is " + copyDone);
}
}
Log.d(TAG, "Copy file success");
return copyDone;
}
也是提示权限问题。
05-24 07:35:35.255 596 1988 D CopyFile: the filename is 1-100_24d7a41fcc56e8e00a317eeda9de68a3.jpg
05-24 07:35:35.265 596 1988 W System.err: java.io.FileNotFoundException: /mnt/sdcard/Android/data/xxx/xxx/xxx/xxx/1-100_24d7a41fcc56e8e00a317eeda9de68a3.jpg: open failed: EACCES (Permission denied)
05-24 07:35:35.266 596 1988 W System.err: at libcore.io.IoBridge.open(IoBridge.java:492)
05-24 07:35:35.267 596 1988 W System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
05-24 07:35:35.267 596 1988 W System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:125)
05-24 07:35:35.267 596 1988 W System.err: at com.android.systemui.CopyFileInitReceiver.copy(CopyFileInitReceiver.java:115)
05-24 07:35:35.271 298 308 I adbd : jdwp connection from 1989
05-24 07:35:35.274 596 1988 W System.err: at com.android.systemui.CopyFileInitReceiver$CopyFileThread.run(CopyFileInitReceiver.java:62)
05-24 07:35:35.274 596 1988 W System.err: at java.lang.Thread.run(Thread.java:923)
05-24 07:35:35.275 596 1988 W System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
05-24 07:35:35.275 596 1988 W System.err: at libcore.io.Linux.open(Native Method)
05-24 07:35:35.276 596 1988 W System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
05-24 07:35:35.276 596 1988 W System.err: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254)
05-24 07:35:35.276 596 1988 W System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:166)
05-24 07:35:35.276 596 1988 W System.err: at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7573)
05-24 07:35:35.276 596 1988 W System.err: at libcore.io.IoBridge.open(IoBridge.java:478)
2.首先定位到App的外部私有目录(Android/data/)的创建位置:
grep "Android/data/" * -Rn
A100_R11.0\frameworks\base\services\core\java\com\android\server\StorageManagerService.java
==========================================================================
private final class StorageManagerInternalImpl extends StorageManagerInternal {
...
/**
* Check if fuse is running in target user, if it's running then setup its storage dirs.
* Return true if storage dirs are mounted.
*/
@Override
public boolean prepareStorageDirs(int userId, Set<String> packageList,
String processName) {
synchronized (mLock) {
if (!mFuseMountedUser.contains(userId)) {
Slog.w(TAG, "User " + userId + " is not unlocked yet so skip mounting obb");
return false;
}
}
try {
final IVold vold = IVold.Stub.asInterface(
ServiceManager.getServiceOrThrow("vold"));
for (String pkg : packageList) {
final String packageObbDir =
String.format("/storage/emulated/%d/Android/obb/%s/", userId, pkg);
final String packageDataDir =
String.format("/storage/emulated/%d/Android/data/%s/",
userId, pkg);
// Create package obb and data dir if it doesn't exist.
int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
File file = new File(packageObbDir);
if (!file.exists()) {
vold.setupAppDir(packageObbDir, appUid);
}
file = new File(packageDataDir);
if (!file.exists()) {
vold.setupAppDir(packageDataDir, appUid);
}
}
} catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
Slog.e(TAG, "Unable to create obb and data directories for " + processName,e);
return false;
}
return true;
}
...
}
//那么就监听一下开机广播,然后创建客户需要的目录
private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Preconditions.checkArgument(userId >= 0);
try {
if (Intent.ACTION_USER_ADDED.equals(action)) {
final UserManager um = mContext.getSystemService(UserManager.class);
final int userSerialNumber = um.getUserSerialNumber(userId);
mVold.onUserAdded(userId, userSerialNumber);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
synchronized (mVolumes) {
final int size = mVolumes.size();
for (int i = 0; i < size; i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
if (vol.mountUserId == userId) {
vol.mountUserId = UserHandle.USER_NULL;
mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
}
}
}
mVold.onUserRemoved(userId);
}else if(Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
try {
final IVold vold = IVold.Stub.asInterface(
ServiceManager.getServiceOrThrow("vold"));
String pkg = "xxx";
Slog.e(TAG, "UserHandle.USER_SYSTEM= " +UserHandle.USER_SYSTEM +",userId="+userId);
// userId =UserHandle.USER_SYSTEM;
//int userId = 0;
final String packageObbDir =
String.format("/storage/emulated/%d/Android/obb/%s/", userId, pkg);
final String packageDataDir1 =
String.format("/storage/emulated/%d/Android/data/%s/sites/data/filepool",
userId, pkg);
// Create package obb and data dir if it doesn't exist.
int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
int appUid1 = UserHandle.getUid(UserHandle.USER_ALL, mPmInternal.getPackage(pkg).getUid());
Slog.e(TAG, "filestore appUid= " + appUid+",appUid1="+appUid1);
File file = new File(packageObbDir);
if (!file.exists()) {
vold.setupAppDir(packageObbDir, appUid);
}
file = new File(packageDataDir1);
if (!file.exists()) {
//不过这里创建了目录,但是权限不够,第三方应用无法进行文件读写,所以需要授权
vold.setupAppDir(packageDataDir1, appUid);
Slog.e(TAG, "packageDataDir1 appUid= " + appUid);
//创建完成后通知,系统应用copy资源到指定目录
Intent scanIntent = new Intent("android.djdg.setupAppDir");
mContext.sendBroadcast(scanIntent);
}
} catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
Slog.e(TAG, "Unable to create obb and data directories for " +e);
}
}else if ("android.djdg.copy.success".equals(intent.getAction())) {
Slog.e(TAG, "接收广播 android.djdg.copy.success");
try {
final IVold vold = IVold.Stub.asInterface(
ServiceManager.getServiceOrThrow("vold"));
String pkg = "com.mineduapp.aprendoencasa";
final String packageDataDir =
String.format("/storage/emulated/%d/Android/data/%s/sites/data/filepool",
userId, pkg);
// Create package obb and data dir if it doesn't exist.
int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
Slog.e(TAG, "filestore appUid= " + appUid);
File file = new File(packageDataDir);
vold.fixupAppDir(packageDataDir, appUid);
Slog.e(TAG, "fixupAppDir packageDataDir appUid= " + appUid);
} catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
Slog.e(TAG, "Unable to create obb and data directories for " +e);
}
}
} catch (Exception e) {
Slog.wtf(TAG, e);
}
}
};
给文件夹授权,更具AIDL服务的方法定位
A100_R11.0\system\vold\VoldNativeService.cpp
=============================================================
binder::Status VoldNativeService::setupAppDir(const std::string& path, int32_t appUid) {
ENFORCE_SYSTEM_OR_ROOT;
CHECK_ARGUMENT_PATH(path);
ACQUIRE_LOCK;
return translate(VolumeManager::Instance()->setupAppDir(path, appUid));
}
A100_R11.0\system\vold\VolumeManager.cpp
=============================================================
int VolumeManager::setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly) {
// Only offer to create directories for paths managed by vold
if (!StartsWith(path, "/storage/")) {
LOG(ERROR) << "Failed to find mounted volume for " << path;
return -EINVAL;
}
// Find the volume it belongs to
auto filter_fn = [&](const VolumeBase& vol) {
if (vol.getState() != VolumeBase::State::kMounted) {
// The volume must be mounted
return false;
}
if ((vol.getMountFlags() & VolumeBase::MountFlags::kVisible) == 0) {
// and visible
return false;
}
if (vol.getInternalPath().empty()) {
return false;
}
if (vol.getMountUserId() != USER_UNKNOWN &&
vol.getMountUserId() != multiuser_get_user_id(appUid)) {
// The app dir must be created on a volume with the same user-id
return false;
}
if (!path.empty() && StartsWith(path, vol.getPath())) {
return true;
}
return false;
};
auto volume = findVolumeWithFilter(filter_fn);
if (volume == nullptr) {
LOG(ERROR) << "Failed to find mounted volume for " << path;
return -EINVAL;
}
// Convert paths to lower filesystem paths to avoid making FUSE requests for these reasons:
// 1. A FUSE request from vold puts vold at risk of hanging if the FUSE daemon is down
// 2. The FUSE daemon prevents requests on /mnt/user/0/emulated/<userid != 0> and a request
// on /storage/emulated/10 means /mnt/user/0/emulated/10
const std::string lowerPath =
volume->getInternalPath() + path.substr(volume->getPath().length());
const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0
if (fixupExistingOnly && (access(lowerPath.c_str(), F_OK) != 0)) {
// Nothing to fixup
return OK;
}
if (volume->getType() == VolumeBase::Type::kPublic) {
// On public volumes, we don't need to setup permissions, as everything goes through
// FUSE; just create the dirs and be done with it.
return fs_mkdirs(lowerPath.c_str(), 0700);
}
// Create the app paths we need from the root
return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid, fixupExistingOnly);
}
int VolumeManager::fixupAppDir(const std::string& path, int32_t appUid) {
if (IsSdcardfsUsed()) {
//sdcardfs magically does this for us
return OK;
}
return setupAppDir(path, appUid, true /* fixupExistingOnly */);
}
##最后确认App的外部私有目录授权是在 A100_R11.0\system\vold\Utils.cpp文件
A100_R11.0\system\vold\Utils.cpp
=============================================================
int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
bool fixupExisting) {
long projectId;
size_t pos;
int ret = 0;
bool sdcardfsSupport = IsSdcardfsUsed();
// Make sure the Android/ directories exist and are setup correctly
ret = PrepareAndroidDirs(root);
if (ret != 0) {
LOG(ERROR) << "Failed to prepare Android/ directories.";
return ret;
}
// Now create the application-specific subdir(s)
// path is something like /data/media/0/Android/data/com.foo/files
// First, chop off the volume root, eg /data/media/0
std::string pathFromRoot = path.substr(root.length());
uid_t uid = appUid;
gid_t gid = AID_MEDIA_RW;
std::vector<gid_t> additionalGids;
std::string appDir;
// Check that the next part matches one of the allowed Android/ dirs
if (StartsWith(pathFromRoot, kAppDataDir)) {
appDir = kAppDataDir;
if (!sdcardfsSupport) {
gid = AID_EXT_DATA_RW;
// Also add the app's own UID as a group; since apps belong to a group
// that matches their UID, this ensures that they will always have access to
// the files created in these dirs, even if they are created by other processes
additionalGids.push_back(uid);
}
} else if (StartsWith(pathFromRoot, kAppMediaDir)) {
appDir = kAppMediaDir;
if (!sdcardfsSupport) {
gid = AID_MEDIA_RW;
}
} else if (StartsWith(pathFromRoot, kAppObbDir)) {
appDir = kAppObbDir;
if (!sdcardfsSupport) {
gid = AID_EXT_OBB_RW;
// See comments for kAppDataDir above
additionalGids.push_back(uid);
}
} else {
LOG(ERROR) << "Invalid application directory: " << path;
return -EINVAL;
}
// mode = 770, plus sticky bit on directory to inherit GID when apps
// create subdirs
//在这里对文件进行授权
/*mode_t mode = S_IRWXU | S_IRWXG | S_ISGID ;*/
/********update start ********/
std::string::size_type n;
mode_t mode ;
if ((n = pathFromRoot.find("xxx")) != std::string::npos) {
mode = S_IRWXU | S_IRWXG | S_ISGID | S_IRWXO ;
}else{
mode = S_IRWXU | S_IRWXG | S_ISGID ;
}
/********update end********/
.............
return OK;
}
mode_t 是文件权限值。
#define S_IFMT 00170000
13#define S_IFSOCK 0140000
14#define S_IFLNK 0120000
15#define S_IFREG 0100000
16#define S_IFBLK 0060000
17#define S_IFDIR 0040000
18#define S_IFCHR 0020000
19#define S_IFIFO 0010000
20#define S_ISUID 0004000
21#define S_ISGID 0002000
22#define S_ISVTX 0001000
23
24#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
25#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
26#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
27#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
28#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
29#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
30#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
31
32#define S_IRWXU 00700
33#define S_IRUSR 00400
34#define S_IWUSR 00200
35#define S_IXUSR 00100
36
37#define S_IRWXG 00070
38#define S_IRGRP 00040
39#define S_IWGRP 00020
40#define S_IXGRP 00010
41
42#define S_IRWXO 00007
43#define S_IROTH 00004
44#define S_IWOTH 00002
45#define S_IXOTH 00001
46
47#endif
48
49#ifdef __KERNEL__
50#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
51#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
52#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
53#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
54#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
Linux
头文件库:
#include <sys/stat.h>
#include <sys/types.h>
函数原型:
int mkdir(const char *pathname, mode_t mode);
函数说明:
mkdir()函数以mode方式创建一个以参数pathname命名的目录,mode定义新创建目录的权限。
返回值:
若目录创建成功,则返回0;否则返回-1,并将错误记录到全局变量errno中。
mode方式:可多个权限相或,如0777表示mode = S_IRWXU | S_IRWXG | S_ISGID | S_IRWXO
代表:该文件所有者拥有读,写和执行操作的权限,该文件用户组拥有可读、可执行的权限,其他用户拥有可读、可执行的权限。
文件copy完成后,如果需要重新复原目录权限的话需要调用fixupAppDir方法来进行修正,可以自定义一个广播来通知修正
int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid,
bool fixupExisting) {
........
if (fixupExisting && access(pathToCreate.c_str(), F_OK) == 0) {
// Fixup all files in this existing directory with the correct UID/GID
// and project ID.
mode = S_IRWXU | S_IRWXG | S_ISGID ;
//LOG(ERROR) << "fixupExisting: " << pathToCreate.c_str();
ret = FixupAppDir(pathToCreate, mode, uid, gid, projectId);
ret = 0;//这里做一下修正处理,不做处理user版本会有些问题,应用读取不了数据
} else {
ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId);
}
if (ret != 0) {
return ret;
}
if (depth == 0) {
// Set the default ACL on the top-level application-specific directories,
// to ensure that even if applications run with a umask of 0077,
// new directories within these directories will allow the GID
// specified here to write; this is necessary for apps like
// installers and MTP, that require access here.
//
// See man (5) acl for more details.
ret = SetDefaultAcl(pathToCreate, mode, uid, gid, additionalGids);
if (ret != 0) {
return ret;
}
if (!sdcardfsSupport) {
// Set project ID inheritance, so that future subdirectories inherit the
// same project ID
ret = SetQuotaInherit(pathToCreate);
if (ret != 0) {
return ret;
}
}
}
depth++;
}
copy完成后通知一下服务进行修正,
try {
Intent intent = new Intent("android.djdg.copy.success");
//Intent.EXTRA_USER_HANDLE,StorageManagerService.java 广播接收器里面有做参数解析,所以带上参数避免导致系统重启
intent.putExtra("android.intent.extra.user_handle",0);
mContext.sendBroadcastAsUser(intent, new UserHandle(0));
// mContext.sendBroadcast(intent);
}catch (Exception e) {
e.printStackTrace();
}
2022-05-28 09:50:52.057 7376-9977/system_process W/ActivityManager: Unable to start service Intent { act=android.media.IMediaScannerService cmp=com.android.providers.media/.MediaScannerService (has extras) } U=0: not found
2022-05-28 09:50:52.066 7376-9977/system_process E/ActivityManager: Sending non-protected broadcast android.djdg.copy.success from system 7532:com.android.systemui/u0a97 pkg com.android.systemui
java.lang.Throwable
at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:15999)
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16580)
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16016)
at com.android.server.am.ActivityManagerService.broadcastIntentWithFeature(ActivityManagerService.java:16832)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2267)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2890)
at android.os.Binder.execTransactInternal(Binder.java:1159)
at android.os.Binder.execTransact(Binder.java:1123)
2022-05-28 09:50:52.068 7376-9977/system_process E/ActivityManager: Sending non-protected broadcast android.djdg.copy.success from system 7532:com.android.systemui/u0a97 pkg com.android.systemui
java.lang.Throwable
at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:15999)
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16676)
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:16016)
at com.android.server.am.ActivityManagerService.broadcastIntentWithFeature(ActivityManagerService.java:16832)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2267)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2890)
at android.os.Binder.execTransactInternal(Binder.java:1159)
at android.os.Binder.execTransact(Binder.java:1123)
2022-05-28 09:50:52.072 7376-7407/system_process I/DropBoxManagerService: add tag=system_server_wtf isTagEnabled=true flags=0x2
2022-05-28 09:50:52.084 7376-7460/system_process E/AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: StorageManagerService
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.djdg.copy.success flg=0x10 } in com.android.server.StorageManagerService$1@c560dac
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1590)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.os.HandlerThread.run(HandlerThread.java:67)
Caused by: java.lang.IllegalArgumentException
at com.android.internal.util.Preconditions.checkArgument(Preconditions.java:37)
at com.android.server.StorageManagerService$1.onReceive(StorageManagerService.java:852)
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1580)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.os.HandlerThread.run(HandlerThread.java:67)
方式2:也可以直接更改映射地址到oem目录去,省去开机copy的步骤;
方式3:直接修改File.java文件,线判断(Android/data/)是否有文件存在,如果没有就去oem分区下查找数据,如果有则重定向目录至oem/下的位置(此方式未验证);
./libcore/ojluni/src/main/java/java/io/File.java
================================================================================
/**
* Creates a new <code>File</code> instance by converting the given
* pathname string into an abstract pathname. If the given string is
* the empty string, then the result is the empty abstract pathname.
*
* @param pathname A pathname string
* @throws NullPointerException
* If the <code>pathname</code> argument is <code>null</code>
*/
public File(String pathname) {
if (pathname == null) {
throw new NullPointerException();
}
String tempPath = fs.normalize(pathname);
this.path = exitPath(tempPath);
this.prefixLength = fs.prefixLength(this.path);
}
/**
* Avoid dead cycles
* @param path File path
* @return File path
*/
public File(String pathname,boolean bool) {
if (pathname == null) {
throw new NullPointerException();
}
this.path = fs.normalize(pathname);
this.prefixLength = fs.prefixLength(this.path);
}
其他几个构造函数也是这样处理
....
String tempPath = fs.normalize(p);
this.path = exitPath(tempPath);
this.prefixLength = fs.prefixLength(this.path);
....
/**
* Partial address special handling
* @param path File path
* @return File path
*/
private String exitPath(String path){
String packageNameFile= "xxx/xxx";
if (path.contains(packageNameFile) && path.contains("/Android/data/")){
File file =new File(path,false);
if (!file.exists()){
String oem = "/mnt/oem/";
int _pathIndex= path.indexOf("/Android/data/");
String tmpTop = path.substring(0,_pathIndex);
String pathTemp = path.replace(tmpTop,oem);
java.lang.System.out.print("File pathTemp="+pathTemp);
file = new File(pathTemp,false);
if (file.exists()){
return file.getPath();
}
}
}
return path;
}