package android.telephony.mbms;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.telephony.MbmsDownloadSession;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;
public class MbmsTempFileProvider extends ContentProvider {
public static final String TEMP_FILE_ROOT_PREF_FILE_NAME = "MbmsTempFileRootPrefs";
public static final String TEMP_FILE_ROOT_PREF_NAME = "mbms_temp_file_root";
private String mAuthority;
private Context mContext;
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable String selection, @Nullable String[] selectionArgs,
@Nullable String sortOrder) {
throw new UnsupportedOperationException("No querying supported");
}
@Override
public String getType(@NonNull Uri uri) {
return "application/octet-stream";
}
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
throw new UnsupportedOperationException("No inserting supported");
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) {
throw new UnsupportedOperationException("No deleting supported");
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String
selection, @Nullable String[] selectionArgs) {
throw new UnsupportedOperationException("No updating supported");
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
final File file = getFileForUri(mContext, mAuthority, uri);
final int fileMode = ParcelFileDescriptor.parseMode(mode);
return ParcelFileDescriptor.open(file, fileMode);
}
@Override
public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info);
if (info.exported) {
throw new SecurityException("Provider must not be exported");
}
if (!info.grantUriPermissions) {
throw new SecurityException("Provider must grant uri permissions");
}
mAuthority = info.authority;
mContext = context;
}
public static Uri getUriForFile(Context context, String authority, File file) {
String filePath;
try {
filePath = file.getCanonicalPath();
} catch (IOException e) {
throw new IllegalArgumentException("Could not get canonical path for file " + file);
}
File tempFileDir = getEmbmsTempFileDir(context);
if (!MbmsUtils.isContainedIn(tempFileDir, file)) {
throw new IllegalArgumentException("File " + file + " is not contained in the temp " +
"file directory, which is " + tempFileDir);
}
String tempFileDirPath;
try {
tempFileDirPath = tempFileDir.getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException(
"Could not get canonical path for temp file root dir " + tempFileDir);
}
String pathFragment;
if (tempFileDirPath.endsWith("/")) {
pathFragment = filePath.substring(tempFileDirPath.length());
} else {
pathFragment = filePath.substring(tempFileDirPath.length() + 1);
}
String encodedPath = Uri.encode(pathFragment);
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority).encodedPath(encodedPath).build();
}
public static File getFileForUri(Context context, String authority, Uri uri)
throws FileNotFoundException {
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
throw new IllegalArgumentException("Uri must have scheme content");
}
if (!Objects.equals(authority, uri.getAuthority())) {
throw new IllegalArgumentException("Uri does not have a matching authority: " +
authority + ", " + uri.getAuthority());
}
String relPath = Uri.decode(uri.getEncodedPath());
File file;
File tempFileDir;
try {
tempFileDir = getEmbmsTempFileDir(context).getCanonicalFile();
file = new File(tempFileDir, relPath).getCanonicalFile();
} catch (IOException e) {
throw new FileNotFoundException("Could not resolve paths");
}
if (!file.getPath().startsWith(tempFileDir.getPath())) {
throw new SecurityException("Resolved path jumped beyond configured root");
}
return file;
}
public static File getEmbmsTempFileDir(Context context) {
SharedPreferences prefs = context.getSharedPreferences(TEMP_FILE_ROOT_PREF_FILE_NAME, 0);
String storedTempFileRoot = prefs.getString(TEMP_FILE_ROOT_PREF_NAME, null);
try {
if (storedTempFileRoot != null) {
return new File(storedTempFileRoot).getCanonicalFile();
} else {
return new File(context.getFilesDir(),
MbmsDownloadSession.DEFAULT_TOP_LEVEL_TEMP_DIRECTORY).getCanonicalFile();
}
} catch (IOException e) {
throw new RuntimeException("Unable to canonicalize temp file root path " + e);
}
}
}