Merge cherrypicks of [2780928, 2780896, 2781450, 2781451, 2781452, 2781453, 2781454, 2781169, 2781470, 2781471, 2781472, 2781473, 2781474, 2780929, 2781185, 2781490, 2781491, 2781492, 2781493, 2781494, 2781495, 2781496, 2781497, 2781437, 2781498, 2781499, 2781500, 2781501, 2781502, 2781503, 2781504, 2781505, 2781506, 2781507, 2780897, 2780898, 2780899, 2780900, 2780901, 2781475, 2781476, 2781477, 2781478, 2781186, 2781511, 2781512, 2781630] into nyc-bugfix-release
Change-Id: I071717d1c0a8f735f9135d6fad2f11ecab11f247
diff --git a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
index c2cd172..14a0fd0 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppHandoverReceiver.java
@@ -50,7 +50,7 @@
// Save type/stream, will be used when adding transfer
// session to DB.
BluetoothOppManager.getInstance(context).saveSendingFileInfo(type,
- stream.toString(), true);
+ stream.toString(), true /* isHandover */, true /* fromExternal */);
} else {
if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
}
@@ -60,7 +60,7 @@
uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
if (mimeType != null && uris != null) {
BluetoothOppManager.getInstance(context).saveSendingFileInfo(mimeType,
- uris, true);
+ uris, true /* isHandover */, true /* fromExternal */);
} else {
if (D) Log.d(TAG, "No mimeType or stream attached to handover request");
return;
diff --git a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java
index 0d4b5b2..c298745 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppLauncherActivity.java
@@ -112,7 +112,8 @@
Thread t = new Thread(new Runnable() {
public void run() {
BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this)
- .saveSendingFileInfo(type,stream.toString(), false);
+ .saveSendingFileInfo(type,stream.toString(),
+ false /* isHandover */, true /* fromExternal */);
//Done getting file info..Launch device picker and finish this activity
launchDevicePicker();
finish();
@@ -128,7 +129,8 @@
Thread t = new Thread(new Runnable() {
public void run() {
BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this)
- .saveSendingFileInfo(type,fileUri.toString(), false);
+ .saveSendingFileInfo(type,fileUri.toString(),
+ false /* isHandover */, false /* fromExternal */);
//Done getting file info..Launch device picker
//and finish this activity
launchDevicePicker();
@@ -156,7 +158,8 @@
Thread t = new Thread(new Runnable() {
public void run() {
BluetoothOppManager.getInstance(BluetoothOppLauncherActivity.this)
- .saveSendingFileInfo(mimeType,uris, false);
+ .saveSendingFileInfo(mimeType,uris,
+ false /* isHandover */, true /* fromExternal */);
//Done getting file info..Launch device picker
//and finish this activity
launchDevicePicker();
diff --git a/src/com/android/bluetooth/opp/BluetoothOppManager.java b/src/com/android/bluetooth/opp/BluetoothOppManager.java
index dd8efe0..8e6bfcd 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppManager.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppManager.java
@@ -246,7 +246,7 @@
if (V) Log.v(TAG, "Application data stored to SharedPreference! ");
}
- public void saveSendingFileInfo(String mimeType, String uriString, boolean isHandover) {
+ public void saveSendingFileInfo(String mimeType, String uriString, boolean isHandover, boolean fromExternal) {
synchronized (BluetoothOppManager.this) {
mMultipleFlag = false;
mMimeTypeOfSendingFile = mimeType;
@@ -254,12 +254,12 @@
mIsHandoverInitiated = isHandover;
Uri uri = Uri.parse(uriString);
BluetoothOppUtility.putSendFileInfo(uri,
- BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType));
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType, fromExternal));
storeApplicationData();
}
}
- public void saveSendingFileInfo(String mimeType, ArrayList<Uri> uris, boolean isHandover) {
+ public void saveSendingFileInfo(String mimeType, ArrayList<Uri> uris, boolean isHandover, boolean fromExternal) {
synchronized (BluetoothOppManager.this) {
mMultipleFlag = true;
mMimeTypeOfSendingFiles = mimeType;
@@ -267,7 +267,7 @@
mIsHandoverInitiated = isHandover;
for (Uri uri : uris) {
BluetoothOppUtility.putSendFileInfo(uri,
- BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType));
+ BluetoothOppSendFileInfo.generateFileInfo(mContext, uri, mimeType, fromExternal));
}
storeApplicationData();
}
diff --git a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
index b8cb641..0df0452 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppSendFileInfo.java
@@ -39,6 +39,7 @@
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.provider.OpenableColumns;
+import android.util.EventLog;
import android.util.Log;
import java.io.File;
@@ -98,7 +99,7 @@
}
public static BluetoothOppSendFileInfo generateFileInfo(Context context, Uri uri,
- String type) {
+ String type, boolean fromExternal) {
ContentResolver contentResolver = context.getContentResolver();
String scheme = uri.getScheme();
String fileName = null;
@@ -136,6 +137,15 @@
fileName = uri.getLastPathSegment();
}
} else if ("file".equals(scheme)) {
+ if (uri.getPath() == null) {
+ Log.e(TAG, "Invalid URI path: " + uri);
+ return SEND_FILE_INFO_ERROR;
+ }
+ if (fromExternal && !BluetoothOppUtility.isInExternalStorageDir(uri)) {
+ EventLog.writeEvent(0x534e4554, "35310991", -1, uri.getPath());
+ Log.e(TAG, "File based URI not in Environment.getExternalStorageDirectory() is not allowed.");
+ return SEND_FILE_INFO_ERROR;
+ }
fileName = uri.getLastPathSegment();
contentType = type;
File f = new File(uri.getPath());
diff --git a/src/com/android/bluetooth/opp/BluetoothOppUtility.java b/src/com/android/bluetooth/opp/BluetoothOppUtility.java
index ab4613f..03c3f12 100644
--- a/src/com/android/bluetooth/opp/BluetoothOppUtility.java
+++ b/src/com/android/bluetooth/opp/BluetoothOppUtility.java
@@ -39,6 +39,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.net.Uri;
+import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.ActivityNotFoundException;
@@ -46,6 +47,7 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
+import android.os.Environment;
import android.util.Log;
import java.io.File;
@@ -66,6 +68,10 @@
private static final ConcurrentHashMap<Uri, BluetoothOppSendFileInfo> sSendFileMap
= new ConcurrentHashMap<Uri, BluetoothOppSendFileInfo>();
+ public static boolean isBluetoothShareUri(Uri uri) {
+ return uri.toString().startsWith(BluetoothShare.CONTENT_URI.toString());
+ }
+
public static BluetoothOppTransferInfo queryRecord(Context context, Uri uri) {
BluetoothOppTransferInfo info = new BluetoothOppTransferInfo();
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
@@ -176,6 +182,11 @@
return;
}
+ if (!isBluetoothShareUri(uri)) {
+ Log.e(TAG, "Trying to open a file that wasn't transfered over Bluetooth");
+ return;
+ }
+
File f = new File(fileName);
if (!f.exists()) {
Intent in = new Intent(context, BluetoothOppBtErrorActivity.class);
@@ -206,17 +217,8 @@
.queryIntentActivities(activityIntent,
PackageManager.MATCH_DEFAULT_ONLY);
- // Grant permissions for any app that can handle a file to access it
- for (ResolveInfo resolveInfo : resInfoList) {
- String packageName = resolveInfo.activityInfo.packageName;
- context.grantUriPermission(packageName, path,
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
- }
-
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- activityIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- activityIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ activityIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
if (V) Log.d(TAG, "ACTION_VIEW intent sent out: " + path + " / " + mimetype);
@@ -350,4 +352,40 @@
}
}
}
+
+ /**
+ * Checks if the URI is in Environment.getExternalStorageDirectory() as it
+ * is the only directory that is possibly readable by both the sender and
+ * the Bluetooth process.
+ */
+ static boolean isInExternalStorageDir(Uri uri) {
+ if (!ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
+ Log.e(TAG, "Not a file URI: " + uri);
+ return false;
+ }
+ final File file = new File(uri.getCanonicalUri().getPath());
+ return isSameOrSubDirectory(Environment.getExternalStorageDirectory(), file);
+ }
+
+ /**
+ * Checks, whether the child directory is the same as, or a sub-directory of the base
+ * directory. Neither base nor child should be null.
+ */
+ static boolean isSameOrSubDirectory(File base, File child) {
+ try {
+ base = base.getCanonicalFile();
+ child = child.getCanonicalFile();
+ File parentFile = child;
+ while (parentFile != null) {
+ if (base.equals(parentFile)) {
+ return true;
+ }
+ parentFile = parentFile.getParentFile();
+ }
+ return false;
+ } catch (IOException ex) {
+ Log.e(TAG, "Error while accessing file", ex);
+ return false;
+ }
+ }
}