Drm encode mms parts while persisting the pdu
Bug 5158047 Change-Id: I88aba9a91192fb1eb730b48efad3b2b488abad3d
This commit is contained in:
@@ -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,9 +878,67 @@ 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(
|
||||
long msgId, int type, EncodedStringValue[] array) {
|
||||
// Delete old address information and then insert new ones.
|
||||
|
||||
111
core/java/com/google/android/mms/util/DownloadDrmHelper.java
Normal file
111
core/java/com/google/android/mms/util/DownloadDrmHelper.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
172
core/java/com/google/android/mms/util/DrmConvertSession.java
Normal file
172
core/java/com/google/android/mms/util/DrmConvertSession.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user