summaryrefslogtreecommitdiffstats
path: root/core/java/com/google
diff options
context:
space:
mode:
authorTom Taylor <tomtaylor@google.com>2012-03-27 15:42:16 -0700
committerTom Taylor <tomtaylor@google.com>2012-03-27 15:42:16 -0700
commitca184870ca6db8cda264a466582f19e71f7233cd (patch)
tree08505a7511b280879424818480e47262521b5d28 /core/java/com/google
parent8b5bce8d9060c1b68b5605da8f6978d8fb5ea1d3 (diff)
downloadframeworks_base-ca184870ca6db8cda264a466582f19e71f7233cd.zip
frameworks_base-ca184870ca6db8cda264a466582f19e71f7233cd.tar.gz
frameworks_base-ca184870ca6db8cda264a466582f19e71f7233cd.tar.bz2
Drm encode mms parts while persisting the pdu
Bug 5158047 Change-Id: I88aba9a91192fb1eb730b48efad3b2b488abad3d
Diffstat (limited to 'core/java/com/google')
-rw-r--r--core/java/com/google/android/mms/pdu/PduPersister.java124
-rw-r--r--core/java/com/google/android/mms/util/DownloadDrmHelper.java111
-rw-r--r--core/java/com/google/android/mms/util/DrmConvertSession.java172
3 files changed, 404 insertions, 3 deletions
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index b04f890..7c937ed 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -20,6 +20,8 @@ package com.google.android.mms.pdu;
import com.google.android.mms.ContentType;
import com.google.android.mms.InvalidHeaderValueException;
import com.google.android.mms.MmsException;
+import com.google.android.mms.util.DownloadDrmHelper;
+import com.google.android.mms.util.DrmConvertSession;
import com.google.android.mms.util.PduCache;
import com.google.android.mms.util.PduCacheEntry;
import com.google.android.mms.util.SqliteWrapper;
@@ -30,7 +32,11 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteException;
+import android.drm.DrmManagerClient;
import android.net.Uri;
+import android.os.FileUtils;
+import android.provider.MediaStore;
import android.provider.Telephony;
import android.provider.Telephony.Mms;
import android.provider.Telephony.MmsSms;
@@ -42,6 +48,7 @@ import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
+import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -271,10 +278,12 @@ public class PduPersister {
private final Context mContext;
private final ContentResolver mContentResolver;
+ private final DrmManagerClient mDrmManagerClient;
private PduPersister(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
+ mDrmManagerClient = new DrmManagerClient(context);
}
/** Get(or create if not exist) an instance of PduPersister */
@@ -761,6 +770,9 @@ public class PduPersister {
throws MmsException {
OutputStream os = null;
InputStream is = null;
+ DrmConvertSession drmConvertSession = null;
+ Uri dataUri = null;
+ String path = null;
try {
byte[] data = part.getData();
@@ -773,9 +785,38 @@ public class PduPersister {
throw new MmsException("unable to update " + uri.toString());
}
} else {
+ boolean isDrm = DownloadDrmHelper.isDrmConvertNeeded(contentType);
+ if (isDrm) {
+ if (uri != null) {
+ try {
+ path = convertUriToPath(mContext, uri);
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "drm uri: " + uri + " path: " + path);
+ }
+ File f = new File(path);
+ long len = f.length();
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "drm path: " + path + " len: " + len);
+ }
+ if (len > 0) {
+ // we're not going to re-persist and re-encrypt an already
+ // converted drm file
+ return;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Can't get file info for: " + part.getDataUri(), e);
+ }
+ }
+ // We haven't converted the file yet, start the conversion
+ drmConvertSession = DrmConvertSession.open(mContext, contentType);
+ if (drmConvertSession == null) {
+ throw new MmsException("Mimetype " + contentType +
+ " can not be converted.");
+ }
+ }
os = mContentResolver.openOutputStream(uri);
if (data == null) {
- Uri dataUri = part.getDataUri();
+ dataUri = part.getDataUri();
if ((dataUri == null) || (dataUri == uri)) {
Log.w(TAG, "Can't find data for this part.");
return;
@@ -788,13 +829,32 @@ public class PduPersister {
byte[] buffer = new byte[8192];
for (int len = 0; (len = is.read(buffer)) != -1; ) {
- os.write(buffer, 0, len);
+ if (!isDrm) {
+ os.write(buffer, 0, len);
+ } else {
+ byte[] convertedData = drmConvertSession.convert(buffer, len);
+ if (convertedData != null) {
+ os.write(convertedData, 0, convertedData.length);
+ } else {
+ throw new MmsException("Error converting drm data.");
+ }
+ }
}
} else {
if (LOCAL_LOGV) {
Log.v(TAG, "Saving data to: " + uri);
}
- os.write(data);
+ if (!isDrm) {
+ os.write(data);
+ } else {
+ dataUri = uri;
+ byte[] convertedData = drmConvertSession.convert(data, data.length);
+ if (convertedData != null) {
+ os.write(convertedData, 0, convertedData.length);
+ } else {
+ throw new MmsException("Error converting drm data.");
+ }
+ }
}
}
} catch (FileNotFoundException e) {
@@ -818,7 +878,65 @@ public class PduPersister {
Log.e(TAG, "IOException while closing: " + is, e);
} // Ignore
}
+ if (drmConvertSession != null) {
+ drmConvertSession.close(path);
+
+ // Reset the permissions on the encrypted part file so everyone has only read
+ // permission.
+ File f = new File(path);
+ ContentValues values = new ContentValues(0);
+ SqliteWrapper.update(mContext, mContentResolver,
+ Uri.parse("content://mms/resetFilePerm/" + f.getName()),
+ values, null, null);
+ }
+ }
+ }
+
+ /**
+ * This method expects uri in the following format
+ * content://media/<table_name>/<row_index> (or)
+ * file://sdcard/test.mp4
+ * http://test.com/test.mp4
+ *
+ * Here <table_name> shall be "video" or "audio" or "images"
+ * <row_index> the index of the content in given table
+ */
+ static public String convertUriToPath(Context context, Uri uri) {
+ String path = null;
+ if (null != uri) {
+ String scheme = uri.getScheme();
+ if (null == scheme || scheme.equals("") ||
+ scheme.equals(ContentResolver.SCHEME_FILE)) {
+ path = uri.getPath();
+
+ } else if (scheme.equals("http")) {
+ path = uri.toString();
+
+ } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
+ String[] projection = new String[] {MediaStore.MediaColumns.DATA};
+ Cursor cursor = null;
+ try {
+ cursor = context.getContentResolver().query(uri, projection, null,
+ null, null);
+ if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
+ throw new IllegalArgumentException("Given Uri could not be found" +
+ " in media store");
+ }
+ int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
+ path = cursor.getString(pathIndex);
+ } catch (SQLiteException e) {
+ throw new IllegalArgumentException("Given Uri is not formatted in a way " +
+ "so that it can be found in media store.");
+ } finally {
+ if (null != cursor) {
+ cursor.close();
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Given Uri scheme is not supported");
+ }
}
+ return path;
}
private void updateAddress(
diff --git a/core/java/com/google/android/mms/util/DownloadDrmHelper.java b/core/java/com/google/android/mms/util/DownloadDrmHelper.java
new file mode 100644
index 0000000..6852eca
--- /dev/null
+++ b/core/java/com/google/android/mms/util/DownloadDrmHelper.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ */
+
+package com.google.android.mms.util;
+
+import android.content.Context;
+import android.drm.DrmManagerClient;
+import android.util.Log;
+
+public class DownloadDrmHelper {
+ private static final String TAG = "DownloadDrmHelper";
+
+ /** The MIME type of special DRM files */
+ public static final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
+
+ /** The extensions of special DRM files */
+ public static final String EXTENSION_DRM_MESSAGE = ".dm";
+
+ public static final String EXTENSION_INTERNAL_FWDL = ".fl";
+
+ /**
+ * Checks if the Media Type is a DRM Media Type
+ *
+ * @param drmManagerClient A DrmManagerClient
+ * @param mimetype Media Type to check
+ * @return True if the Media Type is DRM else false
+ */
+ public static boolean isDrmMimeType(Context context, String mimetype) {
+ boolean result = false;
+ if (context != null) {
+ try {
+ DrmManagerClient drmClient = new DrmManagerClient(context);
+ if (drmClient != null && mimetype != null && mimetype.length() > 0) {
+ result = drmClient.canHandle("", mimetype);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG,
+ "DrmManagerClient instance could not be created, context is Illegal.");
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Checks if the Media Type needs to be DRM converted
+ *
+ * @param mimetype Media type of the content
+ * @return True if convert is needed else false
+ */
+ public static boolean isDrmConvertNeeded(String mimetype) {
+ return MIMETYPE_DRM_MESSAGE.equals(mimetype);
+ }
+
+ /**
+ * Modifies the file extension for a DRM Forward Lock file NOTE: This
+ * function shouldn't be called if the file shouldn't be DRM converted
+ */
+ public static String modifyDrmFwLockFileExtension(String filename) {
+ if (filename != null) {
+ int extensionIndex;
+ extensionIndex = filename.lastIndexOf(".");
+ if (extensionIndex != -1) {
+ filename = filename.substring(0, extensionIndex);
+ }
+ filename = filename.concat(EXTENSION_INTERNAL_FWDL);
+ }
+ return filename;
+ }
+
+ /**
+ * Gets the original mime type of DRM protected content.
+ *
+ * @param context The context
+ * @param path Path to the file
+ * @param containingMime The current mime type of of the file i.e. the
+ * containing mime type
+ * @return The original mime type of the file if DRM protected else the
+ * currentMime
+ */
+ public static String getOriginalMimeType(Context context, String path, String containingMime) {
+ String result = containingMime;
+ DrmManagerClient drmClient = new DrmManagerClient(context);
+ try {
+ if (drmClient.canHandle(path, null)) {
+ result = drmClient.getOriginalMimeType(path);
+ }
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG,
+ "Can't get original mime type since path is null or empty string.");
+ } catch (IllegalStateException ex) {
+ Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+ }
+ return result;
+ }
+}
diff --git a/core/java/com/google/android/mms/util/DrmConvertSession.java b/core/java/com/google/android/mms/util/DrmConvertSession.java
new file mode 100644
index 0000000..2d8f274
--- /dev/null
+++ b/core/java/com/google/android/mms/util/DrmConvertSession.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ */
+package com.google.android.mms.util;
+
+import android.content.Context;
+import android.drm.DrmConvertedStatus;
+import android.drm.DrmManagerClient;
+import android.util.Log;
+import android.provider.Downloads;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+
+public class DrmConvertSession {
+ private DrmManagerClient mDrmClient;
+ private int mConvertSessionId;
+ private static final String TAG = "DrmConvertSession";
+
+ private DrmConvertSession(DrmManagerClient drmClient, int convertSessionId) {
+ mDrmClient = drmClient;
+ mConvertSessionId = convertSessionId;
+ }
+
+ /**
+ * Start of converting a file.
+ *
+ * @param context The context of the application running the convert session.
+ * @param mimeType Mimetype of content that shall be converted.
+ * @return A convert session or null in case an error occurs.
+ */
+ public static DrmConvertSession open(Context context, String mimeType) {
+ DrmManagerClient drmClient = null;
+ int convertSessionId = -1;
+ if (context != null && mimeType != null && !mimeType.equals("")) {
+ try {
+ drmClient = new DrmManagerClient(context);
+ try {
+ convertSessionId = drmClient.openConvertSession(mimeType);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Conversion of Mimetype: " + mimeType
+ + " is not supported.", e);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not access Open DrmFramework.", e);
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG,
+ "DrmManagerClient instance could not be created, context is Illegal.");
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+ }
+ }
+
+ if (drmClient == null || convertSessionId < 0) {
+ return null;
+ } else {
+ return new DrmConvertSession(drmClient, convertSessionId);
+ }
+ }
+ /**
+ * Convert a buffer of data to protected format.
+ *
+ * @param buffer Buffer filled with data to convert.
+ * @param size The number of bytes that shall be converted.
+ * @return A Buffer filled with converted data, if execution is ok, in all
+ * other case null.
+ */
+ public byte [] convert(byte[] inBuffer, int size) {
+ byte[] result = null;
+ if (inBuffer != null) {
+ DrmConvertedStatus convertedStatus = null;
+ try {
+ if (size != inBuffer.length) {
+ byte[] buf = new byte[size];
+ System.arraycopy(inBuffer, 0, buf, 0, size);
+ convertedStatus = mDrmClient.convertData(mConvertSessionId, buf);
+ } else {
+ convertedStatus = mDrmClient.convertData(mConvertSessionId, inBuffer);
+ }
+
+ if (convertedStatus != null &&
+ convertedStatus.statusCode == DrmConvertedStatus.STATUS_OK &&
+ convertedStatus.convertedData != null) {
+ result = convertedStatus.convertedData;
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
+ + mConvertSessionId, e);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not convert data. Convertsession: " +
+ mConvertSessionId, e);
+ }
+ } else {
+ throw new IllegalArgumentException("Parameter inBuffer is null");
+ }
+ return result;
+ }
+
+ /**
+ * Ends a conversion session of a file.
+ *
+ * @param fileName The filename of the converted file.
+ * @return Downloads.Impl.STATUS_SUCCESS if execution is ok.
+ * Downloads.Impl.STATUS_FILE_ERROR in case converted file can not
+ * be accessed. Downloads.Impl.STATUS_NOT_ACCEPTABLE if a problem
+ * occurs when accessing drm framework.
+ * Downloads.Impl.STATUS_UNKNOWN_ERROR if a general error occurred.
+ */
+ public int close(String filename) {
+ DrmConvertedStatus convertedStatus = null;
+ int result = Downloads.Impl.STATUS_UNKNOWN_ERROR;
+ if (mDrmClient != null && mConvertSessionId >= 0) {
+ try {
+ convertedStatus = mDrmClient.closeConvertSession(mConvertSessionId);
+ if (convertedStatus == null ||
+ convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+ convertedStatus.convertedData == null) {
+ result = Downloads.Impl.STATUS_NOT_ACCEPTABLE;
+ } else {
+ RandomAccessFile rndAccessFile = null;
+ try {
+ rndAccessFile = new RandomAccessFile(filename, "rw");
+ rndAccessFile.seek(convertedStatus.offset);
+ rndAccessFile.write(convertedStatus.convertedData);
+ result = Downloads.Impl.STATUS_SUCCESS;
+ } catch (FileNotFoundException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(TAG, "File: " + filename + " could not be found.", e);
+ } catch (IOException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(TAG, "Could not access File: " + filename + " .", e);
+ } catch (IllegalArgumentException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(TAG, "Could not open file in mode: rw", e);
+ } catch (SecurityException e) {
+ Log.w(TAG, "Access to File: " + filename +
+ " was denied denied by SecurityManager.", e);
+ } finally {
+ if (rndAccessFile != null) {
+ try {
+ rndAccessFile.close();
+ } catch (IOException e) {
+ result = Downloads.Impl.STATUS_FILE_ERROR;
+ Log.w(TAG, "Failed to close File:" + filename
+ + ".", e);
+ }
+ }
+ }
+ }
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not close convertsession. Convertsession: " +
+ mConvertSessionId, e);
+ }
+ }
+ return result;
+ }
+}