DrmManagerClient.java revision d074e30ce44b9e33da43b67a4515b8986ca72b26
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.drm; 18 19import android.content.ContentValues; 20import android.content.Context; 21import android.os.Handler; 22import android.os.Looper; 23import android.os.Message; 24import android.util.Log; 25 26import java.io.IOException; 27import java.lang.ref.WeakReference; 28import java.util.ArrayList; 29 30/** 31 * Interface of DRM Framework. 32 * Java application will instantiate this class 33 * to access DRM agent through DRM Framework. 34 * 35 */ 36public class DrmManagerClient { 37 private static final String TAG = "DrmManager"; 38 39 static { 40 // Load the respective library 41 System.loadLibrary("drmframework_jni"); 42 } 43 44 /** 45 * Interface definition of a callback to be invoked to communicate 46 * some info and/or warning about DrmManagerClient. 47 */ 48 public interface OnInfoListener { 49 /** 50 * Called to indicate an info or a warning. 51 * 52 * @param client DrmManagerClient instance 53 * @param event instance which wraps reason and necessary information 54 */ 55 public void onInfo(DrmManagerClient client, DrmInfoEvent event); 56 } 57 58 private static final int STATE_UNINITIALIZED = 0x00000000; 59 private static final int STATE_INITIALIZED = 0x00000001; 60 61 private int mUniqueId; 62 private int mNativeContext; 63 private EventHandler mEventHandler; 64 private OnInfoListener mOnInfoListener; 65 private int mCurrentState = STATE_UNINITIALIZED; 66 67 /** 68 * {@hide} 69 */ 70 public static void notify(Object thisReference, int uniqueId, int infoType, String message) { 71 DrmManagerClient instance = (DrmManagerClient)((WeakReference)thisReference).get(); 72 73 if (null != instance && null != instance.mEventHandler) { 74 Message m = instance.mEventHandler.obtainMessage( 75 EventHandler.INFO_EVENT_TYPE, uniqueId, infoType, message); 76 instance.mEventHandler.sendMessage(m); 77 } 78 } 79 80 private class EventHandler extends Handler { 81 public static final int INFO_EVENT_TYPE = 1; 82 83 public EventHandler(Looper looper) { 84 super(looper); 85 } 86 87 public void handleMessage(Message msg) { 88 89 switch (msg.what) { 90 case EventHandler.INFO_EVENT_TYPE: 91 int uniqueId = msg.arg1; 92 int infoType = msg.arg2; 93 String message = msg.obj.toString(); 94 95 if (infoType == DrmInfoEvent.TYPE_REMOVE_RIGHTS) { 96 try { 97 DrmUtils.removeFile(message); 98 } catch (IOException e) { 99 e.printStackTrace(); 100 } 101 } 102 103 if (null != mOnInfoListener) { 104 DrmInfoEvent event = new DrmInfoEvent(uniqueId, infoType, message); 105 mOnInfoListener.onInfo(DrmManagerClient.this, event); 106 } 107 return; 108 default: 109 Log.e(TAG, "Unknown message type " + msg.what); 110 return; 111 } 112 } 113 } 114 115 /** 116 * To instantiate DrmManagerClient 117 * 118 * @param context context of the caller 119 */ 120 public DrmManagerClient(Context context) { 121 Looper looper; 122 123 if (null != (looper = Looper.myLooper())) { 124 mEventHandler = new EventHandler(looper); 125 } else if (null != (looper = Looper.getMainLooper())) { 126 mEventHandler = new EventHandler(looper); 127 } else { 128 mEventHandler = null; 129 } 130 131 // save the unique id 132 mUniqueId = hashCode(); 133 } 134 135 /** 136 * Register a callback to be invoked when the caller required to receive 137 * necessary information 138 * 139 * @param infoListener 140 */ 141 public void setOnInfoListener(OnInfoListener infoListener) { 142 synchronized(this) { 143 if (null != infoListener) { 144 mOnInfoListener = infoListener; 145 } 146 } 147 } 148 149 /** 150 * Initializes DrmFramework, which loads all available plug-ins 151 * in the default plug-in directory path 152 * 153 */ 154 public void loadPlugIns() { 155 if (getState() == STATE_UNINITIALIZED) { 156 _loadPlugIns(mUniqueId, new WeakReference<DrmManagerClient>(this)); 157 158 mCurrentState = STATE_INITIALIZED; 159 } 160 } 161 162 /** 163 * Finalize DrmFramework, which release resources associated with each plug-in 164 * and unload all plug-ins. 165 */ 166 public void unloadPlugIns() { 167 if (getState() == STATE_INITIALIZED) { 168 _unloadPlugIns(mUniqueId); 169 170 mCurrentState = STATE_UNINITIALIZED; 171 } 172 } 173 174 /** 175 * Retrieves informations about all the plug-ins registered with DrmFramework. 176 * 177 * @return Array of DrmEngine plug-in strings 178 */ 179 public String[] getAvailableDrmEngines() { 180 if (getState() == STATE_UNINITIALIZED) { 181 throw new IllegalStateException("Not Initialized yet"); 182 } 183 184 DrmSupportInfo[] supportInfos = _getAllSupportInfo(mUniqueId); 185 ArrayList<String> descriptions = new ArrayList<String>(); 186 187 for (int i = 0; i < supportInfos.length; i++) { 188 descriptions.add(supportInfos[i].getDescriprition()); 189 } 190 191 String[] drmEngines = new String[descriptions.size()]; 192 return descriptions.toArray(drmEngines); 193 } 194 195 /** 196 * Get constraints information evaluated from DRM content 197 * 198 * @param path Content path from where DRM constraints would be retrieved. 199 * @param action Actions defined in {@link DrmStore.Action} 200 * @return ContentValues instance in which constraints key-value pairs are embedded 201 * or null in case of failure 202 */ 203 public ContentValues getConstraints(String path, int action) { 204 if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) { 205 throw new IllegalArgumentException("Given usage or path is invalid/null"); 206 } else if (getState() == STATE_UNINITIALIZED) { 207 throw new IllegalStateException("Not Initialized yet"); 208 } 209 return _getConstraints(mUniqueId, path, action); 210 } 211 212 /** 213 * Save DRM rights to specified rights path 214 * and make association with content path. 215 * 216 * @param drmRights DrmRights to be saved 217 * @param rightsPath File path where rights to be saved 218 * @param contentPath File path where content was saved 219 * @throws IOException if failed to save rights information in the given path 220 * 221 * @note In case of OMA or WM-DRM, rightsPath and contentPath could be null 222 */ 223 public void saveRights( 224 DrmRights drmRights, String rightsPath, String contentPath) throws IOException { 225 if (null == drmRights || !drmRights.isValid() 226 || null == contentPath || contentPath.equals("")) { 227 throw new IllegalArgumentException("Given drmRights or contentPath is not valid"); 228 } else if (getState() == STATE_UNINITIALIZED) { 229 throw new IllegalStateException("Not Initialized yet"); 230 } 231 if (null != rightsPath && !rightsPath.equals("")) { 232 DrmUtils.writeToFile(rightsPath, drmRights.getData()); 233 } 234 _saveRights(mUniqueId, drmRights, rightsPath, contentPath); 235 } 236 237 /** 238 * Install new DRM Engine Plug-in at the runtime 239 * 240 * @param engineFilePath Path of the plug-in file to be installed 241 * {@hide} 242 */ 243 public void installDrmEngine(String engineFilePath) { 244 if (null == engineFilePath || engineFilePath.equals("")) { 245 throw new IllegalArgumentException( 246 "Given engineFilePath: "+ engineFilePath + "is not valid"); 247 } else if (getState() == STATE_UNINITIALIZED) { 248 throw new IllegalStateException("Not Initialized yet"); 249 } 250 _installDrmEngine(mUniqueId, engineFilePath); 251 } 252 253 /** 254 * Check whether the given mimetype or path can be handled. 255 * 256 * @param path Path of the content to be handled 257 * @param mimeType Mimetype of the object to be handled 258 * @return 259 * true - if the given mimeType or path can be handled 260 * false - cannot be handled. 261 * @note false will be return in case the state is uninitialized 262 */ 263 public boolean canHandle(String path, String mimeType) { 264 if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) { 265 throw new IllegalArgumentException("Path or the mimetype should be non null"); 266 } else if (getState() == STATE_UNINITIALIZED) { 267 throw new IllegalStateException("Not Initialized yet"); 268 } 269 return _canHandle(mUniqueId, path, mimeType); 270 } 271 272 /** 273 * Executes given drm information based on its type 274 * 275 * @param drmInfo Information needs to be processed 276 * @return DrmInfoStatus Instance as a result of processing given input 277 */ 278 public DrmInfoStatus processDrmInfo(DrmInfo drmInfo) { 279 if (null == drmInfo || !drmInfo.isValid()) { 280 throw new IllegalArgumentException("Given drmInfo is invalid/null"); 281 } else if (getState() == STATE_UNINITIALIZED) { 282 throw new IllegalStateException("Not Initialized yet"); 283 } 284 return _processDrmInfo(mUniqueId, drmInfo); 285 } 286 287 /** 288 * Retrieves necessary information for register, unregister or rights acquisition. 289 * 290 * @param drmInfoRequest Request information to retrieve drmInfo 291 * @return DrmInfo Instance as a result of processing given input 292 */ 293 public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) { 294 if (null == drmInfoRequest || !drmInfoRequest.isValid()) { 295 throw new IllegalArgumentException("Given drmInfoRequest is invalid/null"); 296 } else if (getState() == STATE_UNINITIALIZED) { 297 throw new IllegalStateException("Not Initialized yet"); 298 } 299 return _acquireDrmInfo(mUniqueId, drmInfoRequest); 300 } 301 302 /** 303 * Retrieves the type of the protected object (content, rights, etc..) 304 * using specified path or mimetype. At least one parameter should be non null 305 * to retrieve DRM object type 306 * 307 * @param path Path of the content or null. 308 * @param mimeType Mimetype of the content or null. 309 * @return Type of the DRM content. 310 * @see DrmStore.DrmObjectType 311 */ 312 public int getDrmObjectType(String path, String mimeType) { 313 if ((null == path || path.equals("")) && (null == mimeType || mimeType.equals(""))) { 314 throw new IllegalArgumentException("Path or the mimetype should be non null"); 315 } else if (getState() == STATE_UNINITIALIZED) { 316 throw new IllegalStateException("Not Initialized yet"); 317 } 318 return _getDrmObjectType(mUniqueId, path, mimeType); 319 } 320 321 /** 322 * Retrieves the mime type embedded inside the original content 323 * 324 * @param path Path of the protected content 325 * @return Mimetype of the original content, such as "video/mpeg" 326 */ 327 public String getOriginalMimeType(String path) { 328 if (null == path || path.equals("")) { 329 throw new IllegalArgumentException("Given path should be non null"); 330 } else if (getState() == STATE_UNINITIALIZED) { 331 throw new IllegalStateException("Not Initialized yet"); 332 } 333 return _getOriginalMimeType(mUniqueId, path); 334 } 335 336 /** 337 * Check whether the given content has valid rights or not 338 * 339 * @param path Path of the protected content 340 * @return Status of the rights for the protected content 341 * @see DrmStore.RightsStatus 342 */ 343 public int checkRightsStatus(String path) { 344 return checkRightsStatus(path, DrmStore.Action.DEFAULT); 345 } 346 347 /** 348 * Check whether the given content has valid rights or not for specified action. 349 * 350 * @param path Path of the protected content 351 * @param action Action to perform 352 * @return Status of the rights for the protected content 353 * @see DrmStore.RightsStatus 354 */ 355 public int checkRightsStatus(String path, int action) { 356 if (null == path || path.equals("") || !DrmStore.Action.isValid(action)) { 357 throw new IllegalArgumentException("Given path or action is not valid"); 358 } else if (getState() == STATE_UNINITIALIZED) { 359 throw new IllegalStateException("Not Initialized yet"); 360 } 361 return _checkRightsStatus(mUniqueId, path, action); 362 } 363 364 /** 365 * Removes the rights associated with the given protected content 366 * 367 * @param path Path of the protected content 368 */ 369 public void removeRights(String path) { 370 if (null == path || path.equals("")) { 371 throw new IllegalArgumentException("Given path should be non null"); 372 } else if (getState() == STATE_UNINITIALIZED) { 373 throw new IllegalStateException("Not Initialized yet"); 374 } 375 _removeRights(mUniqueId, path); 376 } 377 378 /** 379 * Removes all the rights information of every plug-in associated with 380 * DRM framework. Will be used in master reset 381 */ 382 public void removeAllRights() { 383 if (getState() == STATE_UNINITIALIZED) { 384 throw new IllegalStateException("Not Initialized yet"); 385 } 386 _removeAllRights(mUniqueId); 387 } 388 389 /** 390 * This API is for Forward Lock based DRM scheme. 391 * Each time the application tries to download a new DRM file 392 * which needs to be converted, then the application has to 393 * begin with calling this API. 394 * 395 * @param mimeType Description/MIME type of the input data packet 396 * @return convert ID which will be used for maintaining convert session. 397 */ 398 public int openConvertSession(String mimeType) { 399 if (null == mimeType || mimeType.equals("")) { 400 throw new IllegalArgumentException("Path or the mimeType should be non null"); 401 } else if (getState() == STATE_UNINITIALIZED) { 402 throw new IllegalStateException("Not Initialized yet"); 403 } 404 return _openConvertSession(mUniqueId, mimeType); 405 } 406 407 /** 408 * Accepts and converts the input data which is part of DRM file. 409 * The resultant converted data and the status is returned in the DrmConvertedInfo 410 * object. This method will be called each time there are new block 411 * of data received by the application. 412 * 413 * @param convertId Handle for the convert session 414 * @param inputData Input Data which need to be converted 415 * @return Return object contains the status of the data conversion, 416 * the output converted data and offset. In this case the 417 * application will ignore the offset information. 418 */ 419 public DrmConvertedStatus convertData(int convertId, byte[] inputData) { 420 if (null == inputData || 0 >= inputData.length) { 421 throw new IllegalArgumentException("Given inputData should be non null"); 422 } else if (getState() == STATE_UNINITIALIZED) { 423 throw new IllegalStateException("Not Initialized yet"); 424 } 425 return _convertData(mUniqueId, convertId, inputData); 426 } 427 428 /** 429 * Informs the Drm Agent when there is no more data which need to be converted 430 * or when an error occurs. Upon successful conversion of the complete data, 431 * the agent will inform that where the header and body signature 432 * should be added. This signature appending is needed to integrity 433 * protect the converted file. 434 * 435 * @param convertId Handle for the convert session 436 * @return Return object contains the status of the data conversion, 437 * the header and body signature data. It also informs 438 * the application on which offset these signature data should be appended. 439 */ 440 public DrmConvertedStatus closeConvertSession(int convertId) { 441 if (getState() == STATE_UNINITIALIZED) { 442 throw new IllegalStateException("Not Initialized yet"); 443 } 444 return _closeConvertSession(mUniqueId, convertId); 445 } 446 447 private int getState() { 448 return mCurrentState; 449 } 450 451 // private native interfaces 452 private native void _loadPlugIns(int uniqueId, Object weak_this); 453 454 private native void _unloadPlugIns(int uniqueId); 455 456 private native void _installDrmEngine(int uniqueId, String engineFilepath); 457 458 private native ContentValues _getConstraints(int uniqueId, String path, int usage); 459 460 private native boolean _canHandle(int uniqueId, String path, String mimeType); 461 462 private native DrmInfoStatus _processDrmInfo(int uniqueId, DrmInfo drmInfo); 463 464 private native DrmInfo _acquireDrmInfo(int uniqueId, DrmInfoRequest drmInfoRequest); 465 466 private native void _saveRights( 467 int uniqueId, DrmRights drmRights, String rightsPath, String contentPath); 468 469 private native int _getDrmObjectType(int uniqueId, String path, String mimeType); 470 471 private native String _getOriginalMimeType(int uniqueId, String path); 472 473 private native int _checkRightsStatus(int uniqueId, String path, int action); 474 475 private native void _removeRights(int uniqueId, String path); 476 477 private native void _removeAllRights(int uniqueId); 478 479 private native int _openConvertSession(int uniqueId, String mimeType); 480 481 private native DrmConvertedStatus _convertData(int uniqueId, int convertId, byte[] inputData); 482 483 private native DrmConvertedStatus _closeConvertSession(int uniqueId, int convertId); 484 485 private native DrmSupportInfo[] _getAllSupportInfo(int uniqueId); 486} 487 488