AssetManager.java revision a393735a5d637d211713b2b580bdd16f8eba2f7d
1/*
2 * Copyright (C) 2006 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.content.res;
18
19import android.os.ParcelFileDescriptor;
20import android.util.Log;
21import android.util.TypedValue;
22
23import java.io.FileNotFoundException;
24import java.io.IOException;
25import java.io.InputStream;
26import java.util.HashMap;
27
28/**
29 * Provides access to an application's raw asset files; see {@link Resources}
30 * for the way most applications will want to retrieve their resource data.
31 * This class presents a lower-level API that allows you to open and read raw
32 * files that have been bundled with the application as a simple stream of
33 * bytes.
34 */
35public final class AssetManager {
36    /* modes used when opening an asset */
37
38    /**
39     * Mode for {@link #open(String, int)}: no specific information about how
40     * data will be accessed.
41     */
42    public static final int ACCESS_UNKNOWN = 0;
43    /**
44     * Mode for {@link #open(String, int)}: Read chunks, and seek forward and
45     * backward.
46     */
47    public static final int ACCESS_RANDOM = 1;
48    /**
49     * Mode for {@link #open(String, int)}: Read sequentially, with an
50     * occasional forward seek.
51     */
52    public static final int ACCESS_STREAMING = 2;
53    /**
54     * Mode for {@link #open(String, int)}: Attempt to load contents into
55     * memory, for fast small reads.
56     */
57    public static final int ACCESS_BUFFER = 3;
58
59    private static final String TAG = "AssetManager";
60    private static final boolean localLOGV = false || false;
61
62    private static final boolean DEBUG_REFS = false;
63
64    private static final Object sSync = new Object();
65    /*package*/ static AssetManager sSystem = null;
66
67    private final TypedValue mValue = new TypedValue();
68    private final long[] mOffsets = new long[2];
69
70    // For communication with native code.
71    private long mObject;
72
73    private StringBlock mStringBlocks[] = null;
74
75    private int mNumRefs = 1;
76    private boolean mOpen = true;
77    private HashMap<Long, RuntimeException> mRefStacks;
78
79    /**
80     * Create a new AssetManager containing only the basic system assets.
81     * Applications will not generally use this method, instead retrieving the
82     * appropriate asset manager with {@link Resources#getAssets}.    Not for
83     * use by applications.
84     * {@hide}
85     */
86    public AssetManager() {
87        synchronized (this) {
88            if (DEBUG_REFS) {
89                mNumRefs = 0;
90                incRefsLocked(this.hashCode());
91            }
92            init(false);
93            if (localLOGV) Log.v(TAG, "New asset manager: " + this);
94            ensureSystemAssets();
95        }
96    }
97
98    private static void ensureSystemAssets() {
99        synchronized (sSync) {
100            if (sSystem == null) {
101                AssetManager system = new AssetManager(true);
102                system.makeStringBlocks(false);
103                sSystem = system;
104            }
105        }
106    }
107
108    private AssetManager(boolean isSystem) {
109        if (DEBUG_REFS) {
110            synchronized (this) {
111                mNumRefs = 0;
112                incRefsLocked(this.hashCode());
113            }
114        }
115        init(true);
116        if (localLOGV) Log.v(TAG, "New asset manager: " + this);
117    }
118
119    /**
120     * Return a global shared asset manager that provides access to only
121     * system assets (no application assets).
122     * {@hide}
123     */
124    public static AssetManager getSystem() {
125        ensureSystemAssets();
126        return sSystem;
127    }
128
129    /**
130     * Close this asset manager.
131     */
132    public void close() {
133        synchronized(this) {
134            //System.out.println("Release: num=" + mNumRefs
135            //                   + ", released=" + mReleased);
136            if (mOpen) {
137                mOpen = false;
138                decRefsLocked(this.hashCode());
139            }
140        }
141    }
142
143    /**
144     * Retrieve the string value associated with a particular resource
145     * identifier for the current configuration / skin.
146     */
147    /*package*/ final CharSequence getResourceText(int ident) {
148        synchronized (this) {
149            TypedValue tmpValue = mValue;
150            int block = loadResourceValue(ident, (short) 0, tmpValue, true);
151            if (block >= 0) {
152                if (tmpValue.type == TypedValue.TYPE_STRING) {
153                    return mStringBlocks[block].get(tmpValue.data);
154                }
155                return tmpValue.coerceToString();
156            }
157        }
158        return null;
159    }
160
161    /**
162     * Retrieve the string value associated with a particular resource
163     * identifier for the current configuration / skin.
164     */
165    /*package*/ final CharSequence getResourceBagText(int ident, int bagEntryId) {
166        synchronized (this) {
167            TypedValue tmpValue = mValue;
168            int block = loadResourceBagValue(ident, bagEntryId, tmpValue, true);
169            if (block >= 0) {
170                if (tmpValue.type == TypedValue.TYPE_STRING) {
171                    return mStringBlocks[block].get(tmpValue.data);
172                }
173                return tmpValue.coerceToString();
174            }
175        }
176        return null;
177    }
178
179    /**
180     * Retrieve the string array associated with a particular resource
181     * identifier.
182     * @param id Resource id of the string array
183     */
184    /*package*/ final String[] getResourceStringArray(final int id) {
185        String[] retArray = getArrayStringResource(id);
186        return retArray;
187    }
188
189
190    /*package*/ final boolean getResourceValue(int ident,
191                                               int density,
192                                               TypedValue outValue,
193                                               boolean resolveRefs)
194    {
195        int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
196        if (block >= 0) {
197            if (outValue.type != TypedValue.TYPE_STRING) {
198                return true;
199            }
200            outValue.string = mStringBlocks[block].get(outValue.data);
201            return true;
202        }
203        return false;
204    }
205
206    /**
207     * Retrieve the text array associated with a particular resource
208     * identifier.
209     * @param id Resource id of the string array
210     */
211    /*package*/ final CharSequence[] getResourceTextArray(final int id) {
212        int[] rawInfoArray = getArrayStringInfo(id);
213        int rawInfoArrayLen = rawInfoArray.length;
214        final int infoArrayLen = rawInfoArrayLen / 2;
215        int block;
216        int index;
217        CharSequence[] retArray = new CharSequence[infoArrayLen];
218        for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
219            block = rawInfoArray[i];
220            index = rawInfoArray[i + 1];
221            retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
222        }
223        return retArray;
224    }
225
226    /*package*/ final boolean getThemeValue(long theme, int ident,
227            TypedValue outValue, boolean resolveRefs) {
228        int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs);
229        if (block >= 0) {
230            if (outValue.type != TypedValue.TYPE_STRING) {
231                return true;
232            }
233            StringBlock[] blocks = mStringBlocks;
234            if (blocks == null) {
235                ensureStringBlocks();
236                blocks = mStringBlocks;
237            }
238            outValue.string = blocks[block].get(outValue.data);
239            return true;
240        }
241        return false;
242    }
243
244    /*package*/ final void ensureStringBlocks() {
245        if (mStringBlocks == null) {
246            synchronized (this) {
247                if (mStringBlocks == null) {
248                    makeStringBlocks(true);
249                }
250            }
251        }
252    }
253
254    /*package*/ final void makeStringBlocks(boolean copyFromSystem) {
255        final int sysNum = copyFromSystem ? sSystem.mStringBlocks.length : 0;
256        final int num = getStringBlockCount();
257        mStringBlocks = new StringBlock[num];
258        if (localLOGV) Log.v(TAG, "Making string blocks for " + this
259                + ": " + num);
260        for (int i=0; i<num; i++) {
261            if (i < sysNum) {
262                mStringBlocks[i] = sSystem.mStringBlocks[i];
263            } else {
264                mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true);
265            }
266        }
267    }
268
269    /*package*/ final CharSequence getPooledString(int block, int id) {
270        //System.out.println("Get pooled: block=" + block
271        //                   + ", id=#" + Integer.toHexString(id)
272        //                   + ", blocks=" + mStringBlocks);
273        return mStringBlocks[block-1].get(id);
274    }
275
276    /**
277     * Open an asset using ACCESS_STREAMING mode.  This provides access to
278     * files that have been bundled with an application as assets -- that is,
279     * files placed in to the "assets" directory.
280     *
281     * @param fileName The name of the asset to open.  This name can be
282     *                 hierarchical.
283     *
284     * @see #open(String, int)
285     * @see #list
286     */
287    public final InputStream open(String fileName) throws IOException {
288        return open(fileName, ACCESS_STREAMING);
289    }
290
291    /**
292     * Open an asset using an explicit access mode, returning an InputStream to
293     * read its contents.  This provides access to files that have been bundled
294     * with an application as assets -- that is, files placed in to the
295     * "assets" directory.
296     *
297     * @param fileName The name of the asset to open.  This name can be
298     *                 hierarchical.
299     * @param accessMode Desired access mode for retrieving the data.
300     *
301     * @see #ACCESS_UNKNOWN
302     * @see #ACCESS_STREAMING
303     * @see #ACCESS_RANDOM
304     * @see #ACCESS_BUFFER
305     * @see #open(String)
306     * @see #list
307     */
308    public final InputStream open(String fileName, int accessMode)
309        throws IOException {
310        synchronized (this) {
311            if (!mOpen) {
312                throw new RuntimeException("Assetmanager has been closed");
313            }
314            long asset = openAsset(fileName, accessMode);
315            if (asset != 0) {
316                AssetInputStream res = new AssetInputStream(asset);
317                incRefsLocked(res.hashCode());
318                return res;
319            }
320        }
321        throw new FileNotFoundException("Asset file: " + fileName);
322    }
323
324    public final AssetFileDescriptor openFd(String fileName)
325            throws IOException {
326        synchronized (this) {
327            if (!mOpen) {
328                throw new RuntimeException("Assetmanager has been closed");
329            }
330            ParcelFileDescriptor pfd = openAssetFd(fileName, mOffsets);
331            if (pfd != null) {
332                return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
333            }
334        }
335        throw new FileNotFoundException("Asset file: " + fileName);
336    }
337
338    /**
339     * Return a String array of all the assets at the given path.
340     *
341     * @param path A relative path within the assets, i.e., "docs/home.html".
342     *
343     * @return String[] Array of strings, one for each asset.  These file
344     *         names are relative to 'path'.  You can open the file by
345     *         concatenating 'path' and a name in the returned string (via
346     *         File) and passing that to open().
347     *
348     * @see #open
349     */
350    public native final String[] list(String path)
351        throws IOException;
352
353    /**
354     * {@hide}
355     * Open a non-asset file as an asset using ACCESS_STREAMING mode.  This
356     * provides direct access to all of the files included in an application
357     * package (not only its assets).  Applications should not normally use
358     * this.
359     *
360     * @see #open(String)
361     */
362    public final InputStream openNonAsset(String fileName) throws IOException {
363        return openNonAsset(0, fileName, ACCESS_STREAMING);
364    }
365
366    /**
367     * {@hide}
368     * Open a non-asset file as an asset using a specific access mode.  This
369     * provides direct access to all of the files included in an application
370     * package (not only its assets).  Applications should not normally use
371     * this.
372     *
373     * @see #open(String, int)
374     */
375    public final InputStream openNonAsset(String fileName, int accessMode)
376        throws IOException {
377        return openNonAsset(0, fileName, accessMode);
378    }
379
380    /**
381     * {@hide}
382     * Open a non-asset in a specified package.  Not for use by applications.
383     *
384     * @param cookie Identifier of the package to be opened.
385     * @param fileName Name of the asset to retrieve.
386     */
387    public final InputStream openNonAsset(int cookie, String fileName)
388        throws IOException {
389        return openNonAsset(cookie, fileName, ACCESS_STREAMING);
390    }
391
392    /**
393     * {@hide}
394     * Open a non-asset in a specified package.  Not for use by applications.
395     *
396     * @param cookie Identifier of the package to be opened.
397     * @param fileName Name of the asset to retrieve.
398     * @param accessMode Desired access mode for retrieving the data.
399     */
400    public final InputStream openNonAsset(int cookie, String fileName, int accessMode)
401        throws IOException {
402        synchronized (this) {
403            if (!mOpen) {
404                throw new RuntimeException("Assetmanager has been closed");
405            }
406            long asset = openNonAssetNative(cookie, fileName, accessMode);
407            if (asset != 0) {
408                AssetInputStream res = new AssetInputStream(asset);
409                incRefsLocked(res.hashCode());
410                return res;
411            }
412        }
413        throw new FileNotFoundException("Asset absolute file: " + fileName);
414    }
415
416    public final AssetFileDescriptor openNonAssetFd(String fileName)
417            throws IOException {
418        return openNonAssetFd(0, fileName);
419    }
420
421    public final AssetFileDescriptor openNonAssetFd(int cookie,
422            String fileName) throws IOException {
423        synchronized (this) {
424            if (!mOpen) {
425                throw new RuntimeException("Assetmanager has been closed");
426            }
427            ParcelFileDescriptor pfd = openNonAssetFdNative(cookie,
428                    fileName, mOffsets);
429            if (pfd != null) {
430                return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
431            }
432        }
433        throw new FileNotFoundException("Asset absolute file: " + fileName);
434    }
435
436    /**
437     * Retrieve a parser for a compiled XML file.
438     *
439     * @param fileName The name of the file to retrieve.
440     */
441    public final XmlResourceParser openXmlResourceParser(String fileName)
442            throws IOException {
443        return openXmlResourceParser(0, fileName);
444    }
445
446    /**
447     * Retrieve a parser for a compiled XML file.
448     *
449     * @param cookie Identifier of the package to be opened.
450     * @param fileName The name of the file to retrieve.
451     */
452    public final XmlResourceParser openXmlResourceParser(int cookie,
453            String fileName) throws IOException {
454        XmlBlock block = openXmlBlockAsset(cookie, fileName);
455        XmlResourceParser rp = block.newParser();
456        block.close();
457        return rp;
458    }
459
460    /**
461     * {@hide}
462     * Retrieve a non-asset as a compiled XML file.  Not for use by
463     * applications.
464     *
465     * @param fileName The name of the file to retrieve.
466     */
467    /*package*/ final XmlBlock openXmlBlockAsset(String fileName)
468            throws IOException {
469        return openXmlBlockAsset(0, fileName);
470    }
471
472    /**
473     * {@hide}
474     * Retrieve a non-asset as a compiled XML file.  Not for use by
475     * applications.
476     *
477     * @param cookie Identifier of the package to be opened.
478     * @param fileName Name of the asset to retrieve.
479     */
480    /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName)
481        throws IOException {
482        synchronized (this) {
483            if (!mOpen) {
484                throw new RuntimeException("Assetmanager has been closed");
485            }
486            long xmlBlock = openXmlAssetNative(cookie, fileName);
487            if (xmlBlock != 0) {
488                XmlBlock res = new XmlBlock(this, xmlBlock);
489                incRefsLocked(res.hashCode());
490                return res;
491            }
492        }
493        throw new FileNotFoundException("Asset XML file: " + fileName);
494    }
495
496    /*package*/ void xmlBlockGone(int id) {
497        synchronized (this) {
498            decRefsLocked(id);
499        }
500    }
501
502    /*package*/ final long createTheme() {
503        synchronized (this) {
504            if (!mOpen) {
505                throw new RuntimeException("Assetmanager has been closed");
506            }
507            long res = newTheme();
508            incRefsLocked(res);
509            return res;
510        }
511    }
512
513    /*package*/ final void releaseTheme(long theme) {
514        synchronized (this) {
515            deleteTheme(theme);
516            decRefsLocked(theme);
517        }
518    }
519
520    protected void finalize() throws Throwable {
521        try {
522            if (DEBUG_REFS && mNumRefs != 0) {
523                Log.w(TAG, "AssetManager " + this
524                        + " finalized with non-zero refs: " + mNumRefs);
525                if (mRefStacks != null) {
526                    for (RuntimeException e : mRefStacks.values()) {
527                        Log.w(TAG, "Reference from here", e);
528                    }
529                }
530            }
531            destroy();
532        } finally {
533            super.finalize();
534        }
535    }
536
537    public final class AssetInputStream extends InputStream {
538        /**
539         * @hide
540         */
541        public final int getAssetInt() {
542            throw new UnsupportedOperationException();
543        }
544        /**
545         * @hide
546         */
547        public final long getNativeAsset() {
548            return mAsset;
549        }
550        private AssetInputStream(long asset)
551        {
552            mAsset = asset;
553            mLength = getAssetLength(asset);
554        }
555        public final int read() throws IOException {
556            return readAssetChar(mAsset);
557        }
558        public final boolean markSupported() {
559            return true;
560        }
561        public final int available() throws IOException {
562            long len = getAssetRemainingLength(mAsset);
563            return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len;
564        }
565        public final void close() throws IOException {
566            synchronized (AssetManager.this) {
567                if (mAsset != 0) {
568                    destroyAsset(mAsset);
569                    mAsset = 0;
570                    decRefsLocked(hashCode());
571                }
572            }
573        }
574        public final void mark(int readlimit) {
575            mMarkPos = seekAsset(mAsset, 0, 0);
576        }
577        public final void reset() throws IOException {
578            seekAsset(mAsset, mMarkPos, -1);
579        }
580        public final int read(byte[] b) throws IOException {
581            return readAsset(mAsset, b, 0, b.length);
582        }
583        public final int read(byte[] b, int off, int len) throws IOException {
584            return readAsset(mAsset, b, off, len);
585        }
586        public final long skip(long n) throws IOException {
587            long pos = seekAsset(mAsset, 0, 0);
588            if ((pos+n) > mLength) {
589                n = mLength-pos;
590            }
591            if (n > 0) {
592                seekAsset(mAsset, n, 0);
593            }
594            return n;
595        }
596
597        protected void finalize() throws Throwable
598        {
599            close();
600        }
601
602        private long mAsset;
603        private long mLength;
604        private long mMarkPos;
605    }
606
607    /**
608     * Add an additional set of assets to the asset manager.  This can be
609     * either a directory or ZIP file.  Not for use by applications.  Returns
610     * the cookie of the added asset, or 0 on failure.
611     * {@hide}
612     */
613    public final int addAssetPath(String path) {
614        int res = addAssetPathNative(path);
615        return res;
616    }
617
618    private native final int addAssetPathNative(String path);
619
620     /**
621     * Add a set of assets to overlay an already added set of assets.
622     *
623     * This is only intended for application resources. System wide resources
624     * are handled before any Java code is executed.
625     *
626     * {@hide}
627     */
628    public native final int addOverlayPath(String idmapPath);
629
630    /**
631     * Add multiple sets of assets to the asset manager at once.  See
632     * {@link #addAssetPath(String)} for more information.  Returns array of
633     * cookies for each added asset with 0 indicating failure, or null if
634     * the input array of paths is null.
635     * {@hide}
636     */
637    public final int[] addAssetPaths(String[] paths) {
638        if (paths == null) {
639            return null;
640        }
641
642        int[] cookies = new int[paths.length];
643        for (int i = 0; i < paths.length; i++) {
644            cookies[i] = addAssetPath(paths[i]);
645        }
646
647        return cookies;
648    }
649
650    /**
651     * Determine whether the state in this asset manager is up-to-date with
652     * the files on the filesystem.  If false is returned, you need to
653     * instantiate a new AssetManager class to see the new data.
654     * {@hide}
655     */
656    public native final boolean isUpToDate();
657
658    /**
659     * Change the locale being used by this asset manager.  Not for use by
660     * applications.
661     * {@hide}
662     */
663    public native final void setLocale(String locale);
664
665    /**
666     * Get the locales that this asset manager contains data for.
667     */
668    public native final String[] getLocales();
669
670    /**
671     * Change the configuation used when retrieving resources.  Not for use by
672     * applications.
673     * {@hide}
674     */
675    public native final void setConfiguration(int mcc, int mnc, String locale,
676            int orientation, int touchscreen, int density, int keyboard,
677            int keyboardHidden, int navigation, int screenWidth, int screenHeight,
678            int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
679            int screenLayout, int uiMode, int majorVersion);
680
681    /**
682     * Retrieve the resource identifier for the given resource name.
683     */
684    /*package*/ native final int getResourceIdentifier(String type,
685                                                       String name,
686                                                       String defPackage);
687
688    /*package*/ native final String getResourceName(int resid);
689    /*package*/ native final String getResourcePackageName(int resid);
690    /*package*/ native final String getResourceTypeName(int resid);
691    /*package*/ native final String getResourceEntryName(int resid);
692
693    private native final long openAsset(String fileName, int accessMode);
694    private final native ParcelFileDescriptor openAssetFd(String fileName,
695            long[] outOffsets) throws IOException;
696    private native final long openNonAssetNative(int cookie, String fileName,
697            int accessMode);
698    private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
699            String fileName, long[] outOffsets) throws IOException;
700    private native final void destroyAsset(long asset);
701    private native final int readAssetChar(long asset);
702    private native final int readAsset(long asset, byte[] b, int off, int len);
703    private native final long seekAsset(long asset, long offset, int whence);
704    private native final long getAssetLength(long asset);
705    private native final long getAssetRemainingLength(long asset);
706
707    /** Returns true if the resource was found, filling in mRetStringBlock and
708     *  mRetData. */
709    private native final int loadResourceValue(int ident, short density, TypedValue outValue,
710            boolean resolve);
711    /** Returns true if the resource was found, filling in mRetStringBlock and
712     *  mRetData. */
713    private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
714                                               boolean resolve);
715    /*package*/ static final int STYLE_NUM_ENTRIES = 6;
716    /*package*/ static final int STYLE_TYPE = 0;
717    /*package*/ static final int STYLE_DATA = 1;
718    /*package*/ static final int STYLE_ASSET_COOKIE = 2;
719    /*package*/ static final int STYLE_RESOURCE_ID = 3;
720    /*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
721    /*package*/ static final int STYLE_DENSITY = 5;
722    /*package*/ native static final boolean applyStyle(long theme,
723            int defStyleAttr, int defStyleRes, long xmlParser,
724            int[] inAttrs, int[] outValues, int[] outIndices);
725    /*package*/ native final boolean retrieveAttributes(
726            long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
727    /*package*/ native final int getArraySize(int resource);
728    /*package*/ native final int retrieveArray(int resource, int[] outValues);
729    private native final int getStringBlockCount();
730    private native final long getNativeStringBlock(int block);
731
732    /**
733     * {@hide}
734     */
735    public native final String getCookieName(int cookie);
736
737    /**
738     * {@hide}
739     */
740    public native static final int getGlobalAssetCount();
741
742    /**
743     * {@hide}
744     */
745    public native static final String getAssetAllocations();
746
747    /**
748     * {@hide}
749     */
750    public native static final int getGlobalAssetManagerCount();
751
752    private native final long newTheme();
753    private native final void deleteTheme(long theme);
754    /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
755    /*package*/ native static final void copyTheme(long dest, long source);
756    /*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
757                                                                TypedValue outValue,
758                                                                boolean resolve);
759    /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
760
761    private native final long openXmlAssetNative(int cookie, String fileName);
762
763    private native final String[] getArrayStringResource(int arrayRes);
764    private native final int[] getArrayStringInfo(int arrayRes);
765    /*package*/ native final int[] getArrayIntResource(int arrayRes);
766
767    private native final void init(boolean isSystem);
768    private native final void destroy();
769
770    private final void incRefsLocked(long id) {
771        if (DEBUG_REFS) {
772            if (mRefStacks == null) {
773                mRefStacks = new HashMap<Long, RuntimeException>();
774            }
775            RuntimeException ex = new RuntimeException();
776            ex.fillInStackTrace();
777            mRefStacks.put(id, ex);
778        }
779        mNumRefs++;
780    }
781
782    private final void decRefsLocked(long id) {
783        if (DEBUG_REFS && mRefStacks != null) {
784            mRefStacks.remove(id);
785        }
786        mNumRefs--;
787        //System.out.println("Dec streams: mNumRefs=" + mNumRefs
788        //                   + " mReleased=" + mReleased);
789        if (mNumRefs == 0) {
790            destroy();
791        }
792    }
793}
794