• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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 
17 package android.drm.mobile1;
18 
19 import java.io.*;
20 
21 /**
22  * This class provides interfaces to access the DRM raw content.
23  */
24 public class DrmRawContent {
25     /**
26      * The "application/vnd.oma.drm.message" mime type.
27      */
28     public static final String DRM_MIMETYPE_MESSAGE_STRING = "application/vnd.oma.drm.message";
29 
30     /**
31      * The "application/vnd.oma.drm.content" mime type.
32      */
33     public static final String DRM_MIMETYPE_CONTENT_STRING = "application/vnd.oma.drm.content";
34 
35     /**
36      * The DRM delivery type: Forward-Lock
37      */
38     public static final int DRM_FORWARD_LOCK = 1;
39 
40     /**
41      * The DRM delivery type: Combined Delivery
42      */
43     public static final int DRM_COMBINED_DELIVERY = 2;
44 
45     /**
46      * The DRM delivery type: Separate Delivery
47      */
48     public static final int DRM_SEPARATE_DELIVERY = 3;
49 
50     /**
51      * The DRM delivery type: Separate Delivery in DRM message
52      */
53     public static final int DRM_SEPARATE_DELIVERY_DM = 4;
54 
55     /**
56      * The DRM media content length is unknown currently
57      */
58     public static final int DRM_UNKNOWN_DATA_LEN = -1;
59 
60 
61     /**
62      * The id of "application/vnd.oma.drm.message" mime type.
63      */
64     private static final int DRM_MIMETYPE_MESSAGE = 1;
65 
66     /**
67      * The id of "application/vnd.oma.drm.content" mime type.
68      */
69     private static final int DRM_MIMETYPE_CONTENT = 2;
70 
71     /**
72      * Successful operation.
73      */
74     private static final int JNI_DRM_SUCCESS = 0;
75 
76     /**
77      * General failure.
78      */
79     private static final int JNI_DRM_FAILURE = -1;
80 
81     /**
82      * Indicates the end of the DRM content is reached.
83      */
84     private static final int JNI_DRM_EOF = -2;
85 
86     /**
87      * The media content length is unknown from native method
88      */
89     private static final int JNI_DRM_UNKNOWN_DATA_LEN = -3;
90 
91     /**
92      * The member to save the original InputStream data.
93      */
94     private BufferedInputStream inData;
95 
96     /**
97      * The member to save the original InputStream data length.
98      */
99     private int inDataLen;
100 
101     /**
102      * The unique id to this DRM content. It will be initialized
103      * in constructor by native method. And it will not be changed
104      * after initialization.
105      */
106     private int id;
107 
108     /**
109      * The rights issuer address of this DRM object.
110      */
111     private String rightsIssuer;
112 
113     /**
114      * The media content type of this DRM object.
115      */
116     private String mediaType;
117 
118     /**
119      * The delivery method type of this DRM object.
120      */
121     private int rawType;
122 
123 
124     /**
125      * Construct a DrmRawContent object.
126      *
127      * @param inRawdata     object of DRM raw data stream.
128      * @param len           the length of raw data can be read.
129      * @param mimeTypeStr   the mime type of the DRM content.
130      */
DrmRawContent(InputStream inRawdata, int len, String mimeTypeStr)131     public DrmRawContent(InputStream inRawdata, int len, String mimeTypeStr) throws DrmException, IOException {
132         int mimeType;
133 
134         id = -1;
135         inData = new BufferedInputStream(inRawdata, 1024);
136         inDataLen = len;
137 
138         if (DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr))
139             mimeType = DRM_MIMETYPE_MESSAGE;
140         else if (DRM_MIMETYPE_CONTENT_STRING.equals(mimeTypeStr))
141             mimeType = DRM_MIMETYPE_CONTENT;
142         else
143             throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_MESSAGE or DRM_MIMETYPE_CONTENT");
144 
145         if (len <= 0)
146             throw new IllegalArgumentException("len must be > 0");
147 
148         /* call native method to initialize this DRM content */
149         id = nativeConstructDrmContent(inData, inDataLen, mimeType);
150 
151         if (JNI_DRM_FAILURE == id)
152             throw new DrmException("nativeConstructDrmContent() returned JNI_DRM_FAILURE");
153 
154         /* init the rights issuer field. */
155         rightsIssuer = nativeGetRightsAddress();
156 
157         /* init the raw content type. */
158         rawType = nativeGetDeliveryMethod();
159         if (JNI_DRM_FAILURE == rawType)
160             throw new DrmException("nativeGetDeliveryMethod() returned JNI_DRM_FAILURE");
161 
162         /* init the media content type. */
163         mediaType = nativeGetContentType();
164         if (null == mediaType)
165             throw new DrmException("nativeGetContentType() returned null");
166     }
167 
168     /**
169      * Get rights address from raw Seperate Delivery content.
170      *
171      * @return the string of the rights issuer address,
172      *         or null if no rights issuer.
173      */
getRightsAddress()174     public String getRightsAddress() {
175         return rightsIssuer;
176     }
177 
178     /**
179      * Get the type of the raw DRM content.
180      *
181      * @return one of the following delivery type of this DRM content:
182      *              #DRM_FORWARD_LOCK
183      *              #DRM_COMBINED_DELIVERY
184      *              #DRM_SEPARATE_DELIVERY
185      *              #DRM_SEPARATE_DELIVERY_DM
186      */
getRawType()187     public int getRawType() {
188         return rawType;
189     }
190 
191     /**
192      * Get one InputStream object to read decrypted content.
193      *
194      * @param rights        the rights object contain decrypted key.
195      *
196      * @return the InputStream object of decrypted media content.
197      */
getContentInputStream(DrmRights rights)198     public InputStream getContentInputStream(DrmRights rights) {
199         if (null == rights)
200             throw new NullPointerException();
201 
202         return new DrmInputStream(rights);
203     }
204 
205     /**
206      * Get the type of the decrypted media content.
207      *
208      * @return the decrypted media content type of this DRM content.
209      */
getContentType()210     public String getContentType() {
211         return mediaType;
212     }
213 
214     /**
215      * Get the length of the decrypted media content.
216      *
217      * @param rights        the rights object contain decrypted key.
218      *
219      * @return the length of the decrypted media content.
220      *         #DRM_UNKNOWN_DATA_LEN if the length is unknown currently.
221      */
getContentLength(DrmRights rights)222     public int getContentLength(DrmRights rights) throws DrmException {
223         /**
224          * Because currently the media object associate with rights object
225          * has been handled in native logic, so here it is not need to deal
226          * the rights. But for the apps, it is mandatory for user to get
227          * the rights object before get the media content length.
228          */
229         if (null == rights)
230             throw new NullPointerException();
231 
232         int mediaLen = nativeGetContentLength();
233 
234         if (JNI_DRM_FAILURE == mediaLen)
235             throw new DrmException("nativeGetContentLength() returned JNI_DRM_FAILURE");
236 
237         if (JNI_DRM_UNKNOWN_DATA_LEN == mediaLen)
238             return DRM_UNKNOWN_DATA_LEN;
239 
240         return mediaLen;
241     }
242 
243     /**
244      * This class provide a InputStream to the DRM media content.
245      */
246     class DrmInputStream extends InputStream
247     {
248         /**
249          * The flag to indicate whether this stream is closed or not.
250          */
251         private boolean isClosed;
252 
253         /**
254          * The offset of this DRM content to be reset.
255          */
256         private int offset;
257 
258         /**
259          * A byte of data to be readed.
260          */
261         private byte[] b;
262 
263         /**
264          * Construct a DrmInputStream instance.
265          */
DrmInputStream(DrmRights rights)266         public DrmInputStream(DrmRights rights) {
267             /**
268              * Because currently the media object associate with rights object
269              * has been handled in native logic, so here it is not need to deal
270              * the rights. But for the apps, it is mandatory for user to get
271              * the rights object before get the media content data.
272              */
273 
274             isClosed = false;
275             offset = 0;
276             b = new byte[1];
277         }
278 
279         /* Non-javadoc
280          * @see java.io.InputStream#available()
281          */
available()282         public int available() throws IOException {
283             /* call native method to get this DRM decrypted media content length */
284             int len = nativeGetContentLength();
285 
286             if (JNI_DRM_FAILURE == len)
287                 throw new IOException();
288 
289             /* if the length is unknown, just return 0 for available value */
290             if (JNI_DRM_UNKNOWN_DATA_LEN == len)
291                 return 0;
292 
293             int availableLen = len - offset;
294             if (availableLen < 0)
295                 throw new IOException();
296 
297             return availableLen;
298         }
299 
300         /* Non-javadoc
301          * @see java.io.InputStream#read()
302          */
read()303         public int read() throws IOException {
304             int res;
305 
306             res = read(b, 0, 1);
307 
308             if (-1 == res)
309                 return -1;
310 
311             return b[0] & 0xff;
312         }
313 
314         /* Non-javadoc
315          * @see java.io.InputStream#read(byte)
316          */
read(byte[] b)317         public int read(byte[] b) throws IOException {
318             return read(b, 0, b.length);
319         }
320 
321         /* Non-javadoc
322          * @see java.io.InputStream#read(byte, int, int)
323          */
read(byte[] b, int off, int len)324         public int read(byte[] b, int off, int len) throws IOException {
325             if (null == b)
326                 throw new NullPointerException();
327             if (off < 0 || len < 0 || off + len > b.length)
328                 throw new IndexOutOfBoundsException();
329             if (true == isClosed)
330                 throw new IOException();
331 
332             if (0 == len)
333                 return 0;
334 
335             len = nativeReadContent(b, off, len, offset);
336 
337             if (JNI_DRM_FAILURE == len)
338                 throw new IOException();
339             else if (JNI_DRM_EOF == len)
340                 return -1;
341 
342             offset += len;
343 
344             return len;
345         }
346 
347         /* Non-javadoc
348          * @see java.io.InputStream#markSupported()
349          */
markSupported()350         public boolean markSupported() {
351             return false;
352         }
353 
354         /* Non-javadoc
355          * @see java.io.InputStream#mark(int)
356          */
mark(int readlimit)357         public void mark(int readlimit) {
358         }
359 
360         /* Non-javadoc
361          * @see java.io.InputStream#reset()
362          */
reset()363         public void reset() throws IOException {
364             throw new IOException();
365         }
366 
367         /* Non-javadoc
368          * @see java.io.InputStream#skip()
369          */
skip(long n)370         public long skip(long n) throws IOException {
371             return 0;
372         }
373 
374         /* Non-javadoc
375          * @see java.io.InputStream#close()
376          */
close()377         public void close() {
378             isClosed = true;
379         }
380     }
381 
382     /**
383      * native method: construct a DRM content according the mime type.
384      *
385      * @param data      input DRM content data to be parsed.
386      * @param len       the length of the data.
387      * @param mimeType  the mime type of this DRM content. the value of this field includes:
388      *                      #DRM_MIMETYPE_MESSAGE
389      *                      #DRM_MIMETYPE_CONTENT
390      *
391      * @return #the id of the DRM content if succeed.
392      *         #JNI_DRM_FAILURE if fail.
393      */
nativeConstructDrmContent(InputStream data, int len, int mimeType)394     private native int nativeConstructDrmContent(InputStream data, int len, int mimeType);
395 
396     /**
397      * native method: get this DRM content rights issuer.
398      *
399      * @return the address of rights issuer if in case of separate delivery.
400      *         null if not separete delivery, or otherwise.
401      */
nativeGetRightsAddress()402     private native String nativeGetRightsAddress();
403 
404     /**
405      * native method: get this DRM content delivery type.
406      *
407      * @return the delivery method, the value may be one of the following:
408      *              #DRM_FORWARD_LOCK
409      *              #DRM_COMBINED_DELIVERY
410      *              #DRM_SEPARATE_DELIVERY
411      *              #DRM_SEPARATE_DELIVERY_DM
412      *         #JNI_DRM_FAILURE if fail.
413      */
nativeGetDeliveryMethod()414     private native int nativeGetDeliveryMethod();
415 
416     /**
417      * native method: get a piece of media content data.
418      *
419      * @param buf       the buffer to save DRM media content data.
420      * @param bufOff    the offset of the buffer to start to save data.
421      * @param len       the number of byte to read.
422      * @param mediaOff  the offset of the media content data to start to read.
423      *
424      * @return the length of the media content data has been read.
425      *         #JNI_DRM_EOF if reach to end of the media content.
426      *         #JNI_DRM_FAILURE if fail.
427      */
nativeReadContent(byte[] buf, int bufOff, int len, int mediaOff)428     private native int nativeReadContent(byte[] buf, int bufOff, int len, int mediaOff);
429 
430     /**
431      * native method: get this DRM content type.
432      *
433      * @return the decrypted media content type.
434      *         null if fail.
435      */
nativeGetContentType()436     private native String nativeGetContentType();
437 
438     /**
439      * native method: get this DRM decrypted media content length.
440      *
441      * @return the length of decrypted media content.
442      *         #JNI_DRM_FAILURE if fail.
443      *         #JNI_DRM_UNKNOWN_DATA_LEN if the length is unknown currently.
444      */
nativeGetContentLength()445     private native int nativeGetContentLength();
446 
447     /**
448      * The finalizer of the DRMRawContent. Do some cleanup.
449      */
finalize()450     protected native void finalize();
451 
452 
453     /**
454      * Load the shared library to link the native methods.
455      */
456     static {
457         try {
458             System.loadLibrary("drm1_jni");
459         }
460         catch (UnsatisfiedLinkError ule) {
461             System.err.println("WARNING: Could not load libdrm1_jni.so");
462         }
463     }
464 }
465