1d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang/* 2d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Copyright (C) 2017 The Android Open Source Project 3d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 4d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License"); 5d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * you may not use this file except in compliance with the License. 6d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * You may obtain a copy of the License at 7d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 8d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * http://www.apache.org/licenses/LICENSE-2.0 9d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 10d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Unless required by applicable law or agreed to in writing, software 11d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS, 12d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * See the License for the specific language governing permissions and 14d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * limitations under the License. 15d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 16d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 17d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangpackage android.media; 18d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 19d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.annotation.NonNull; 202659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhangimport android.hardware.cas.V1_0.*; 21dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhangimport android.media.MediaCasException.UnsupportedCasException; 222659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhangimport android.os.IHwBinder; 23d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.os.RemoteException; 24dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhangimport android.os.ServiceSpecificException; 25d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport android.util.Log; 26d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 27d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhangimport java.nio.ByteBuffer; 28d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 29d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang/** 30d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaDescrambler class can be used in conjunction with {@link android.media.MediaCodec} 31d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * and {@link android.media.MediaExtractor} to decode media data scrambled by conditional 32d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * access (CA) systems such as those in the ISO/IEC13818-1. 33d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 34d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * A MediaDescrambler object is initialized from a session opened by a MediaCas object, 35d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * and can be used to descramble media streams scrambled with that session's keys. 36d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 37d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Scrambling schemes are identified by 16-bit unsigned integer as in CA_system_id. 38d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 39d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 40addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhangpublic final class MediaDescrambler implements AutoCloseable { 41d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private static final String TAG = "MediaDescrambler"; 422659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang private IDescramblerBase mIDescrambler; 43d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 44d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private final void validateInternalStates() { 45d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mIDescrambler == null) { 46d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalStateException(); 47d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 48d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 49d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 50d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private final void cleanupAndRethrowIllegalState() { 51d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mIDescrambler = null; 52d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalStateException(); 53d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 54d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 55d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 56d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Instantiate a MediaDescrambler. 57d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 58d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param CA_system_id The system id of the scrambling scheme. 59d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 60d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws UnsupportedCasException if the scrambling scheme is not supported. 61d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 62d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public MediaDescrambler(int CA_system_id) throws UnsupportedCasException { 63d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 64d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mIDescrambler = MediaCas.getService().createDescrambler(CA_system_id); 65d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch(Exception e) { 66d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang Log.e(TAG, "Failed to create descrambler: " + e); 67d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mIDescrambler = null; 68d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } finally { 69d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mIDescrambler == null) { 70d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new UnsupportedCasException("Unsupported CA_system_id " + CA_system_id); 71d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 72d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 73d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang native_setup(mIDescrambler.asBinder()); 74d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 75d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 762659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang IHwBinder getBinder() { 77d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 78d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 79d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return mIDescrambler.asBinder(); 80d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 81d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 82d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 83d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Query if the scrambling scheme requires the use of a secure decoder 84d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * to decode data of the given mime type. 85d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 86d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param mime The mime type of the media data 87d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 88d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the descrambler instance is not valid. 89d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 90d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public final boolean requiresSecureDecoderComponent(@NonNull String mime) { 91d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 92d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 93d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 94d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return mIDescrambler.requiresSecureDecoderComponent(mime); 95d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 96d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 97d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 98d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang return true; 99d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 100d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 101d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 102d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Associate a MediaCas session with this MediaDescrambler instance. 103d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * The MediaCas session is used to securely load decryption keys for 104d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * the descrambler. The crypto keys loaded through the MediaCas session 105d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * may be selected for use during the descrambling operation performed 106d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * by {@link android.media.MediaExtractor or @link 107d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * android.media.MediaCodec#queueSecureInputBuffer} by specifying even 108d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * or odd key in the {@link android.media.MediaCodec.CryptoInfo#key} field. 109d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 110addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param session the MediaCas session to associate with this 111d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * MediaDescrambler instance. 112d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 113dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws IllegalStateException if the descrambler instance is not valid. 114dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 115d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 116addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public final void setMediaCasSession(@NonNull MediaCas.Session session) { 117d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 118d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 119d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 1202659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasStateException.throwExceptionIfNeeded( 1212659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang mIDescrambler.setMediaCasSession(session.mSessionId)); 122d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 123d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang cleanupAndRethrowIllegalState(); 124d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 125d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 126d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 127d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang /** 128d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * Descramble a ByteBuffer of data described by a 129d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * {@link android.media.MediaCodec.CryptoInfo} structure. 130d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 131addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param srcBuf ByteBuffer containing the scrambled data, which starts at 132addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * srcBuf.position(). 133addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * @param dstBuf ByteBuffer to hold the descrambled data, which starts at 134addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang * dstBuf.position(). 135d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @param cryptoInfo a {@link android.media.MediaCodec.CryptoInfo} structure 136d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * describing the subsamples contained in src. 137d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 138d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @return number of bytes that have been successfully descrambled, with negative 139d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * values indicating errors. 140d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * 141d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang * @throws IllegalStateException if the descrambler instance is not valid. 142dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang * @throws MediaCasStateException for CAS-specific state exceptions. 143d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang */ 144d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang public final int descramble( 145addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang @NonNull ByteBuffer srcBuf, @NonNull ByteBuffer dstBuf, 146d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @NonNull MediaCodec.CryptoInfo cryptoInfo) { 147d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang validateInternalStates(); 148d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 149d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (cryptoInfo.numSubSamples <= 0) { 150d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalArgumentException( 151d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang "Invalid CryptoInfo: invalid numSubSamples=" + cryptoInfo.numSubSamples); 152d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } else if (cryptoInfo.numBytesOfClearData == null 153d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang && cryptoInfo.numBytesOfEncryptedData == null) { 154d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalArgumentException( 155d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang "Invalid CryptoInfo: clearData and encryptedData size arrays are both null!"); 156d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } else if (cryptoInfo.numBytesOfClearData != null 157d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang && cryptoInfo.numBytesOfClearData.length < cryptoInfo.numSubSamples) { 158d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalArgumentException( 159d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang "Invalid CryptoInfo: numBytesOfClearData is too small!"); 160d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } else if (cryptoInfo.numBytesOfEncryptedData != null 161d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang && cryptoInfo.numBytesOfEncryptedData.length < cryptoInfo.numSubSamples) { 162d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalArgumentException( 163d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang "Invalid CryptoInfo: numBytesOfEncryptedData is too small!"); 164d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } else if (cryptoInfo.key == null || cryptoInfo.key.length != 16) { 165d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang throw new IllegalArgumentException( 166d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang "Invalid CryptoInfo: key array is invalid!"); 167d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 168d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 169dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang try { 170dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang return native_descramble( 171dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang cryptoInfo.key[0], 172dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang cryptoInfo.numSubSamples, 173dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang cryptoInfo.numBytesOfClearData, 174dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang cryptoInfo.numBytesOfEncryptedData, 175addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang srcBuf, srcBuf.position(), srcBuf.limit(), 176addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang dstBuf, dstBuf.position(), dstBuf.limit()); 177dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang } catch (ServiceSpecificException e) { 1782659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang MediaCasStateException.throwExceptionIfNeeded(e.errorCode, e.getMessage()); 1792659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang } catch (RemoteException e) { 1802659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang cleanupAndRethrowIllegalState(); 181dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang } 182dadee0c33e6cb659978ce4fa6aa21f7c384fc43cChong Zhang return -1; 183d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 184d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 185addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang @Override 186addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang public void close() { 187d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang if (mIDescrambler != null) { 188d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang try { 189d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mIDescrambler.release(); 190d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } catch (RemoteException e) { 191d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } finally { 192d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang mIDescrambler = null; 193d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 194d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 195d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang native_release(); 196d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 197d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 198d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang @Override 199d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang protected void finalize() { 200addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang close(); 201d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 202d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 203d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private static native final void native_init(); 2042659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang private native final void native_setup(@NonNull IHwBinder decramblerBinder); 205d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private native final void native_release(); 206d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private native final int native_descramble( 207d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData, 208addc39ec27f3eb9b61ad8565804201a866d16abdChong Zhang @NonNull ByteBuffer srcBuf, int srcOffset, int srcLimit, 2092659c2f16cf55d58f5b3817347340ae84f9eaabdChong Zhang ByteBuffer dstBuf, int dstOffset, int dstLimit) throws RemoteException; 210d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 211d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang static { 212d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang System.loadLibrary("media_jni"); 213d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang native_init(); 214d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang } 215d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang 216d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang private long mNativeContext; 217d5927ae8833780395f8fc5070d0a0a4f8f668292Chong Zhang}