Native.cpp revision 5617ad30c611f373e16bf10c0feec114faef54ef
1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1659b6177e2fa9c9f1f16d7eff57e481f5282afbdaAndy McFadden
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Native method resolution.
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Currently the "Dalvik native" methods are only used for internal methods.
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Someday we may want to export the interface as a faster but riskier
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * alternative to JNI.
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stdlib.h>
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <dlfcn.h>
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void freeSharedLibEntry(void* ptr);
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* lookupSharedLibMethod(const Method* method);
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initialize the native code loader.
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmNativeStartup(void)
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.nativeLibs = dvmHashTableCreate(4, freeSharedLibEntry);
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.nativeLibs == NULL)
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Free up our tables.
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmNativeShutdown(void)
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmHashTableFree(gDvm.nativeLibs);
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gDvm.nativeLibs = NULL;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Resolve a native method and invoke it.
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is executed as if it were a native bridge or function.  If the
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * resolution succeeds, method->insns is replaced, and we don't go through
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * here again.
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Initializes method's class if necessary.
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * An exception is thrown on resolution failure.
6559b6177e2fa9c9f1f16d7eff57e481f5282afbdaAndy McFadden *
6659b6177e2fa9c9f1f16d7eff57e481f5282afbdaAndy McFadden * (This should not be taking "const Method*", because it modifies the
6759b6177e2fa9c9f1f16d7eff57e481f5282afbdaAndy McFadden * structure, but the declaration needs to match the DalvikBridgeFunc
6859b6177e2fa9c9f1f16d7eff57e481f5282afbdaAndy McFadden * type definition.)
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmResolveNativeMethod(const u4* args, JValue* pResult,
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* method, Thread* self)
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ClassObject* clazz = method->clazz;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* func;
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If this is a static method, it could be called before the class
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * has been initialized.
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (dvmIsStaticMethod(method)) {
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert(dvmCheckException(dvmThreadSelf()));
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(dvmIsClassInitialized(clazz) ||
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project               dvmIsClassInitializing(clazz));
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* start with our internal-native methods */
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    func = dvmLookupInternalNativeMethod(method);
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (func != NULL) {
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* resolution always gets the same answer, so no race here */
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IF_LOGVV() {
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGVV("+++ resolved native %s.%s %s, invoking\n",
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                clazz->descriptor, method->name, desc);
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            free(desc);
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmIsSynchronizedMethod(method)) {
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGE("ERROR: internal-native can't be declared 'synchronized'\n");
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGE("Failing on %s.%s\n", method->clazz->descriptor, method->name);
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmAbort();     // harsh, but this is VM-internal problem
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DalvikBridgeFunc dfunc = (DalvikBridgeFunc) func;
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmSetNativeFunc(method, dfunc, NULL);
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(method->insns == NULL);
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dfunc(args, pResult, method, self);
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* now scan any DLLs we have loaded for JNI signatures */
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    func = lookupSharedLibMethod(method);
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (func != NULL) {
11559b6177e2fa9c9f1f16d7eff57e481f5282afbdaAndy McFadden        /* found it, point it at the JNI bridge and then call it */
11659b6177e2fa9c9f1f16d7eff57e481f5282afbdaAndy McFadden        dvmUseJNIBridge((Method*) method, func);
1170083d37b0e1c9e542f671cbca2e9db6819ecccbaAndy McFadden        (*method->nativeFunc)(args, pResult, method, self);
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    IF_LOGW() {
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("No implementation found for native %s.%s %s\n",
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            clazz->descriptor, method->name, desc);
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(desc);
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmThrowException("Ljava/lang/UnsatisfiedLinkError;", method->name);
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ===========================================================================
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      Native shared library support
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ===========================================================================
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// TODO? if a ClassLoader is unloaded, we need to unload all DLLs that
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// are associated with it.  (Or not -- can't determine if native code
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// is still using parts of it.)
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
14270318889578ab67943d6df29fedf09b11cfef015Andy McFaddentypedef enum OnLoadState {
14370318889578ab67943d6df29fedf09b11cfef015Andy McFadden    kOnLoadPending = 0,     /* initial state, must be zero */
14470318889578ab67943d6df29fedf09b11cfef015Andy McFadden    kOnLoadFailed,
14570318889578ab67943d6df29fedf09b11cfef015Andy McFadden    kOnLoadOkay,
14670318889578ab67943d6df29fedf09b11cfef015Andy McFadden} OnLoadState;
14770318889578ab67943d6df29fedf09b11cfef015Andy McFadden
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We add one of these to the hash table for every library we load.  The
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * hash is on the "pathName" field.
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecttypedef struct SharedLib {
15370318889578ab67943d6df29fedf09b11cfef015Andy McFadden    char*       pathName;           /* absolute path to library */
15470318889578ab67943d6df29fedf09b11cfef015Andy McFadden    void*       handle;             /* from dlopen */
15570318889578ab67943d6df29fedf09b11cfef015Andy McFadden    Object*     classLoader;        /* ClassLoader we are associated with */
15670318889578ab67943d6df29fedf09b11cfef015Andy McFadden
15770318889578ab67943d6df29fedf09b11cfef015Andy McFadden    pthread_mutex_t onLoadLock;     /* guards remaining items */
15870318889578ab67943d6df29fedf09b11cfef015Andy McFadden    pthread_cond_t  onLoadCond;     /* wait for JNI_OnLoad in other thread */
15970318889578ab67943d6df29fedf09b11cfef015Andy McFadden    u4              onLoadThreadId; /* recursive invocation guard */
16070318889578ab67943d6df29fedf09b11cfef015Andy McFadden    OnLoadState     onLoadResult;   /* result of earlier JNI_OnLoad */
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} SharedLib;
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (This is a dvmHashTableLookup callback.)
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find an entry that matches the string.
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int hashcmpNameStr(const void* ventry, const void* vname)
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const SharedLib* pLib = (const SharedLib*) ventry;
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* name = (const char*) vname;
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return strcmp(pLib->pathName, name);
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (This is a dvmHashTableLookup callback.)
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find an entry that matches the new entry.
18070318889578ab67943d6df29fedf09b11cfef015Andy McFadden *
18170318889578ab67943d6df29fedf09b11cfef015Andy McFadden * We don't compare the class loader here, because you're not allowed to
18270318889578ab67943d6df29fedf09b11cfef015Andy McFadden * have the same shared library associated with more than one CL.
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int hashcmpSharedLib(const void* ventry, const void* vnewEntry)
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const SharedLib* pLib = (const SharedLib*) ventry;
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const SharedLib* pNewLib = (const SharedLib*) vnewEntry;
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGD("--- comparing %p '%s' %p '%s'\n",
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pLib, pLib->pathName, pNewLib, pNewLib->pathName);
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return strcmp(pLib->pathName, pNewLib->pathName);
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Check to see if an entry with the same pathname already exists.
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
19770318889578ab67943d6df29fedf09b11cfef015Andy McFaddenstatic SharedLib* findSharedLibEntry(const char* pathName)
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u4 hash = dvmComputeUtf8Hash(pathName);
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* ent;
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ent = dvmHashTableLookup(gDvm.nativeLibs, hash, (void*)pathName,
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                hashcmpNameStr, false);
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return ent;
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Add the new entry to the table.
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
21070318889578ab67943d6df29fedf09b11cfef015Andy McFadden * Returns the table entry, which will not be the same as "pLib" if the
21170318889578ab67943d6df29fedf09b11cfef015Andy McFadden * entry already exists.
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
21370318889578ab67943d6df29fedf09b11cfef015Andy McFaddenstatic SharedLib* addSharedLibEntry(SharedLib* pLib)
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u4 hash = dvmComputeUtf8Hash(pLib->pathName);
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Do the lookup with the "add" flag set.  If we add it, we will get
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * our own pointer back.  If somebody beat us to the punch, we'll get
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * their pointer back instead.
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
22270318889578ab67943d6df29fedf09b11cfef015Andy McFadden    return dvmHashTableLookup(gDvm.nativeLibs, hash, pLib, hashcmpSharedLib,
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                true);
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Free up an entry.  (This is a dvmHashTableFree callback.)
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void freeSharedLibEntry(void* ptr)
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SharedLib* pLib = (SharedLib*) ptr;
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Calling dlclose() here is somewhat dangerous, because it's possible
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * that a thread outside the VM is still accessing the code we loaded.
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (false)
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dlclose(pLib->handle);
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(pLib->pathName);
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(pLib);
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Convert library name to system-dependent form, e.g. "jpeg" becomes
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "libjpeg.so".
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (Should we have this take buffer+len and avoid the alloc?  It gets
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * called very rarely.)
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectchar* dvmCreateSystemLibraryName(char* libName)
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char buf[256];
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int len;
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    len = snprintf(buf, sizeof(buf), OS_SHARED_LIB_FORMAT_STR, libName);
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (len >= (int) sizeof(buf))
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    else
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return strdup(buf);
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if 0
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find a library, given the lib's system-dependent name (e.g. "libjpeg.so").
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need to search through the path defined by the java.library.path
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * property.
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns NULL if the library was not found.
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic char* findLibrary(const char* libSysName)
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* javaLibraryPath = NULL;
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* testName = NULL;
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* start;
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* cp;
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool done;
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    javaLibraryPath = dvmGetProperty("java.library.path");
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (javaLibraryPath == NULL)
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGVV("+++ path is '%s'\n", javaLibraryPath);
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    start = cp = javaLibraryPath;
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (cp != NULL) {
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char pathBuf[256];
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int len;
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cp = strchr(start, ':');
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (cp != NULL)
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *cp = '\0';
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        len = snprintf(pathBuf, sizeof(pathBuf), "%s/%s", start, libSysName);
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (len >= (int) sizeof(pathBuf)) {
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGW("Path overflowed %d bytes: '%s' / '%s'\n",
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                len, start, libSysName);
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* keep going, next one might fit */
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGVV("+++  trying '%s'\n", pathBuf);
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (access(pathBuf, R_OK) == 0) {
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                testName = strdup(pathBuf);
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        start = cp +1;
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(javaLibraryPath);
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return testName;
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Load a native shared library, given the system-independent piece of
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the library name.
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Throws an exception on failure.
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmLoadNativeLibrary(StringObject* libNameObj, Object* classLoader)
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* libName = NULL;
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* libSysName = NULL;
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* libPath = NULL;
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If "classLoader" isn't NULL, call the class loader's "findLibrary"
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * method with the lib name.  If it returns a non-NULL result, we use
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * that as the pathname.
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (classLoader != NULL) {
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Method* findLibrary;
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Object* findLibResult;
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        findLibrary = dvmFindVirtualMethodByDescriptor(classLoader->clazz,
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            "findLibrary", "(Ljava/lang/String;)Ljava/lang/String;");
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (findLibrary == NULL) {
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGW("Could not find findLibrary() in %s\n",
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                classLoader->clazz->name);
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmThrowException("Ljava/lang/UnsatisfiedLinkError;",
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                "findLibrary");
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        findLibResult = (Object*)(u4) dvmCallMethod(findLibrary, classLoader,
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                            libNameObj);
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmCheckException()) {
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGV("returning early on exception\n");
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (findLibResult != NULL) {
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* success! */
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            libPath = dvmCreateCstrFromString(libNameObj);
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGI("Found library through CL: '%s'\n", libPath);
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmLoadNativeCode(libPath, classLoader);
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    libName = dvmCreateCstrFromString(libNameObj);
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (libName == NULL)
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    libSysName = dvmCreateSystemLibraryName(libName);
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (libSysName == NULL)
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    libPath = findLibrary(libSysName);
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (libPath != NULL) {
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGD("Found library through path: '%s'\n", libPath);
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmLoadNativeCode(libPath, classLoader);
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGW("Unable to locate shared lib matching '%s'\n", libSysName);
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmThrowException("Ljava/lang/UnsatisfiedLinkError;", libName);
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(libName);
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(libSysName);
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(libPath);
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
38570318889578ab67943d6df29fedf09b11cfef015Andy McFadden
38670318889578ab67943d6df29fedf09b11cfef015Andy McFadden/*
38770318889578ab67943d6df29fedf09b11cfef015Andy McFadden * Check the result of an earlier call to JNI_OnLoad on this library.  If
38870318889578ab67943d6df29fedf09b11cfef015Andy McFadden * the call has not yet finished in another thread, wait for it.
38970318889578ab67943d6df29fedf09b11cfef015Andy McFadden */
39070318889578ab67943d6df29fedf09b11cfef015Andy McFaddenstatic bool checkOnLoadResult(SharedLib* pEntry)
39170318889578ab67943d6df29fedf09b11cfef015Andy McFadden{
39270318889578ab67943d6df29fedf09b11cfef015Andy McFadden    Thread* self = dvmThreadSelf();
39370318889578ab67943d6df29fedf09b11cfef015Andy McFadden    if (pEntry->onLoadThreadId == self->threadId) {
39470318889578ab67943d6df29fedf09b11cfef015Andy McFadden        /*
39570318889578ab67943d6df29fedf09b11cfef015Andy McFadden         * Check this so we don't end up waiting for ourselves.  We need
39670318889578ab67943d6df29fedf09b11cfef015Andy McFadden         * to return "true" so the caller can continue.
39770318889578ab67943d6df29fedf09b11cfef015Andy McFadden         */
39870318889578ab67943d6df29fedf09b11cfef015Andy McFadden        LOGI("threadid=%d: recursive native library load attempt (%s)\n",
39970318889578ab67943d6df29fedf09b11cfef015Andy McFadden            self->threadId, pEntry->pathName);
40070318889578ab67943d6df29fedf09b11cfef015Andy McFadden        return true;
40170318889578ab67943d6df29fedf09b11cfef015Andy McFadden    }
40270318889578ab67943d6df29fedf09b11cfef015Andy McFadden
40370318889578ab67943d6df29fedf09b11cfef015Andy McFadden    LOGV("+++ retrieving %s OnLoad status\n", pEntry->pathName);
40470318889578ab67943d6df29fedf09b11cfef015Andy McFadden    bool result;
40570318889578ab67943d6df29fedf09b11cfef015Andy McFadden
40670318889578ab67943d6df29fedf09b11cfef015Andy McFadden    dvmLockMutex(&pEntry->onLoadLock);
40770318889578ab67943d6df29fedf09b11cfef015Andy McFadden    while (pEntry->onLoadResult == kOnLoadPending) {
40870318889578ab67943d6df29fedf09b11cfef015Andy McFadden        LOGD("threadid=%d: waiting for %s OnLoad status\n",
40970318889578ab67943d6df29fedf09b11cfef015Andy McFadden            self->threadId, pEntry->pathName);
4105617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro        ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
41170318889578ab67943d6df29fedf09b11cfef015Andy McFadden        pthread_cond_wait(&pEntry->onLoadCond, &pEntry->onLoadLock);
41270318889578ab67943d6df29fedf09b11cfef015Andy McFadden        dvmChangeStatus(self, oldStatus);
41370318889578ab67943d6df29fedf09b11cfef015Andy McFadden    }
41470318889578ab67943d6df29fedf09b11cfef015Andy McFadden    if (pEntry->onLoadResult == kOnLoadOkay) {
41570318889578ab67943d6df29fedf09b11cfef015Andy McFadden        LOGV("+++ earlier OnLoad(%s) okay\n", pEntry->pathName);
41670318889578ab67943d6df29fedf09b11cfef015Andy McFadden        result = true;
41770318889578ab67943d6df29fedf09b11cfef015Andy McFadden    } else {
41870318889578ab67943d6df29fedf09b11cfef015Andy McFadden        LOGV("+++ earlier OnLoad(%s) failed\n", pEntry->pathName);
41970318889578ab67943d6df29fedf09b11cfef015Andy McFadden        result = false;
42070318889578ab67943d6df29fedf09b11cfef015Andy McFadden    }
42170318889578ab67943d6df29fedf09b11cfef015Andy McFadden    dvmUnlockMutex(&pEntry->onLoadLock);
42270318889578ab67943d6df29fedf09b11cfef015Andy McFadden    return result;
42370318889578ab67943d6df29fedf09b11cfef015Andy McFadden}
42470318889578ab67943d6df29fedf09b11cfef015Andy McFadden
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecttypedef int (*OnLoadFunc)(JavaVM*, void*);
426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Load native code from the specified absolute pathname.  Per the spec,
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * if we've already loaded a library with the specified pathname, we
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * return without doing anything.
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * TODO? for better results we should absolutify the pathname.  For fully
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * correct results we should stat to get the inode and compare that.  The
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * existing implementation is fine so long as everybody is using
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * System.loadLibrary.
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The library will be associated with the specified class loader.  The JNI
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * spec says we can't load the same library into more than one class loader.
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns "true" on success.
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbool dvmLoadNativeCode(const char* pathName, Object* classLoader)
443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
44470318889578ab67943d6df29fedf09b11cfef015Andy McFadden    SharedLib* pEntry;
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* handle;
446dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden    bool verbose;
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
448dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden    /* reduce noise by not chattering about system libraries */
449dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden    verbose = strncmp(pathName, "/system", sizeof("/system")-1) != 0;
450dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden
451dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden    if (verbose)
452dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden        LOGD("Trying to load lib %s %p\n", pathName, classLoader);
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * See if we've already loaded it.  If we have, and the class loader
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * matches, return successfully without doing anything.
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pEntry = findSharedLibEntry(pathName);
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pEntry != NULL) {
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (pEntry->classLoader != classLoader) {
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGW("Shared lib '%s' already opened by CL %p; can't open in %p\n",
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pathName, pEntry->classLoader, classLoader);
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
465dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden        if (verbose) {
466dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden            LOGD("Shared lib '%s' already loaded in same CL %p\n",
467dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden                pathName, classLoader);
468dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden        }
46970318889578ab67943d6df29fedf09b11cfef015Andy McFadden        if (!checkOnLoadResult(pEntry))
47070318889578ab67943d6df29fedf09b11cfef015Andy McFadden            return false;
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return true;
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Open the shared library.  Because we're using a full path, the system
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * doesn't have to search through LD_LIBRARY_PATH.  (It may do so to
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * resolve this library's dependencies though.)
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
47999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Failures here are expected when java.library.path has several entries
48099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * and we have to hunt for the lib.
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
482dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden     * The current version of the dynamic linker prints detailed information
483dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden     * about dlopen() failures.  Some things to check if the message is
484dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden     * cryptic:
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *   - make sure the library exists on the device
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *   - verify that the right path is being opened (the debug log message
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *     above can help with that)
48899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *   - check to see if the library is valid (e.g. not zero bytes long)
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *   - check config/prelink-linux-arm.map to ensure that the library
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *     is listed and is not being overrun by the previous entry (if
49199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *     loading suddenly stops working on a prelinked library, this is
49299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *     a good one to check)
49399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *   - write a trivial app that calls sleep() then dlopen(), attach
49499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *     to it with "strace -p <pid>" while it sleeps, and watch for
49599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *     attempts to open nonexistent dependent shared libs
4962aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden     *
4972aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden     * This can execute slowly for a large library on a busy system, so we
4982aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden     * want to switch from RUNNING to VMWAIT while it executes.  This allows
4992aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden     * the GC to ignore us.
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
5012aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden    Thread* self = dvmThreadSelf();
5025617ad30c611f373e16bf10c0feec114faef54efCarl Shapiro    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    handle = dlopen(pathName, RTLD_LAZY);
5042aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden    dvmChangeStatus(self, oldStatus);
5052aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (handle == NULL) {
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGI("Unable to dlopen(%s): %s\n", pathName, dlerror());
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
51170318889578ab67943d6df29fedf09b11cfef015Andy McFadden    /* create a new entry */
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SharedLib* pNewEntry;
51370318889578ab67943d6df29fedf09b11cfef015Andy McFadden    pNewEntry = (SharedLib*) calloc(1, sizeof(SharedLib));
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pNewEntry->pathName = strdup(pathName);
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pNewEntry->handle = handle;
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pNewEntry->classLoader = classLoader;
51770318889578ab67943d6df29fedf09b11cfef015Andy McFadden    dvmInitMutex(&pNewEntry->onLoadLock);
51870318889578ab67943d6df29fedf09b11cfef015Andy McFadden    pthread_cond_init(&pNewEntry->onLoadCond, NULL);
51970318889578ab67943d6df29fedf09b11cfef015Andy McFadden    pNewEntry->onLoadThreadId = self->threadId;
52070318889578ab67943d6df29fedf09b11cfef015Andy McFadden
52170318889578ab67943d6df29fedf09b11cfef015Andy McFadden    /* try to add it to the list */
52270318889578ab67943d6df29fedf09b11cfef015Andy McFadden    SharedLib* pActualEntry = addSharedLibEntry(pNewEntry);
52370318889578ab67943d6df29fedf09b11cfef015Andy McFadden
52470318889578ab67943d6df29fedf09b11cfef015Andy McFadden    if (pNewEntry != pActualEntry) {
52570318889578ab67943d6df29fedf09b11cfef015Andy McFadden        LOGI("WOW: we lost a race to add a shared lib (%s CL=%p)\n",
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pathName, classLoader);
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        freeSharedLibEntry(pNewEntry);
52870318889578ab67943d6df29fedf09b11cfef015Andy McFadden        return checkOnLoadResult(pActualEntry);
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
530dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden        if (verbose)
531dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden            LOGD("Added shared lib %s %p\n", pathName, classLoader);
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
53370318889578ab67943d6df29fedf09b11cfef015Andy McFadden        bool result = true;
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void* vonLoad;
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int version;
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        vonLoad = dlsym(handle, "JNI_OnLoad");
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (vonLoad == NULL) {
539dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden            LOGD("No JNI_OnLoad found in %s %p, skipping init\n",
540dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden                pathName, classLoader);
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Call JNI_OnLoad.  We have to override the current class
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * loader, which will always be "null" since the stuff at the
54570318889578ab67943d6df29fedf09b11cfef015Andy McFadden             * top of the stack is around Runtime.loadLibrary().  (See
54670318889578ab67943d6df29fedf09b11cfef015Andy McFadden             * the comments in the JNI FindClass function.)
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            OnLoadFunc func = vonLoad;
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Object* prevOverride = self->classLoaderOverride;
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->classLoaderOverride = classLoader;
5522aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden            oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
55370318889578ab67943d6df29fedf09b11cfef015Andy McFadden            LOGV("+++ calling JNI_OnLoad(%s)\n", pathName);
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            version = (*func)(gDvm.vmList, NULL);
5552aa43610c391868eb6ef80bf3b1f947776defccaAndy McFadden            dvmChangeStatus(self, oldStatus);
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            self->classLoaderOverride = prevOverride;
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 &&
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                version != JNI_VERSION_1_6)
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                LOGW("JNI_OnLoad returned bad version (%d) in %s %p\n",
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    version, pathName, classLoader);
56370318889578ab67943d6df29fedf09b11cfef015Andy McFadden                /*
56470318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 * It's unwise to call dlclose() here, but we can mark it
56570318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 * as bad and ensure that future load attempts will fail.
56670318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 *
56770318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 * We don't know how far JNI_OnLoad got, so there could
56870318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 * be some partially-initialized stuff accessible through
56970318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 * newly-registered native method calls.  We could try to
57070318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 * unregister them, but that doesn't seem worthwhile.
57170318889578ab67943d6df29fedf09b11cfef015Andy McFadden                 */
57270318889578ab67943d6df29fedf09b11cfef015Andy McFadden                result = false;
57370318889578ab67943d6df29fedf09b11cfef015Andy McFadden            } else {
57470318889578ab67943d6df29fedf09b11cfef015Andy McFadden                LOGV("+++ finished JNI_OnLoad %s\n", pathName);
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
57870318889578ab67943d6df29fedf09b11cfef015Andy McFadden        if (result)
57970318889578ab67943d6df29fedf09b11cfef015Andy McFadden            pNewEntry->onLoadResult = kOnLoadOkay;
58070318889578ab67943d6df29fedf09b11cfef015Andy McFadden        else
58170318889578ab67943d6df29fedf09b11cfef015Andy McFadden            pNewEntry->onLoadResult = kOnLoadFailed;
58270318889578ab67943d6df29fedf09b11cfef015Andy McFadden
58370318889578ab67943d6df29fedf09b11cfef015Andy McFadden        pNewEntry->onLoadThreadId = 0;
58470318889578ab67943d6df29fedf09b11cfef015Andy McFadden
58570318889578ab67943d6df29fedf09b11cfef015Andy McFadden        /*
58670318889578ab67943d6df29fedf09b11cfef015Andy McFadden         * Broadcast a wakeup to anybody sleeping on the condition variable.
58770318889578ab67943d6df29fedf09b11cfef015Andy McFadden         */
58870318889578ab67943d6df29fedf09b11cfef015Andy McFadden        dvmLockMutex(&pNewEntry->onLoadLock);
58970318889578ab67943d6df29fedf09b11cfef015Andy McFadden        pthread_cond_broadcast(&pNewEntry->onLoadCond);
59070318889578ab67943d6df29fedf09b11cfef015Andy McFadden        dvmUnlockMutex(&pNewEntry->onLoadLock);
59170318889578ab67943d6df29fedf09b11cfef015Andy McFadden        return result;
59270318889578ab67943d6df29fedf09b11cfef015Andy McFadden    }
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ===========================================================================
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      Signature-based method lookup
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ===========================================================================
600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create the pre-mangled form of the class+method string.
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns a newly-allocated string, and sets "*pLen" to the length.
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic char* createJniNameString(const char* classDescriptor,
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* methodName, int* pLen)
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* result;
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    size_t descriptorLength = strlen(classDescriptor);
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *pLen = 4 + descriptorLength + strlen(methodName);
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = malloc(*pLen +1);
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (result == NULL)
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Add one to classDescriptor to skip the "L", and then replace
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the final ";" with a "/" after the sprintf() call.
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    sprintf(result, "Java/%s%s", classDescriptor + 1, methodName);
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result[5 + (descriptorLength - 2)] = '/';
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns a newly-allocated, mangled copy of "str".
631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * "str" is a "modified UTF-8" string.  We convert it to UTF-16 first to
633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * make life simpler.
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic char* mangleString(const char* str, int len)
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u2* utf16 = NULL;
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* mangle = NULL;
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int charLen;
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //LOGI("mangling '%s' %d\n", str, len);
642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(str[len] == '\0');
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    charLen = dvmUtf8Len(str);
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    utf16 = (u2*) malloc(sizeof(u2) * charLen);
647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (utf16 == NULL)
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmConvertUtf8ToUtf16(utf16, str);
651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Compute the length of the mangled string.
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i, mangleLen = 0;
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0; i < charLen; i++) {
658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        u2 ch = utf16[i];
659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
660dfdaa8733814dd1a576aec0a0a735848384009dfBrian McKenna        if (ch == '$' || ch > 127) {
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            mangleLen += 6;
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (ch) {
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case '_':
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case ';':
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case '[':
667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                mangleLen += 2;
668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            default:
670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                mangleLen++;
671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* cp;
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    mangle = (char*) malloc(mangleLen +1);
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (mangle == NULL)
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0, cp = mangle; i < charLen; i++) {
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        u2 ch = utf16[i];
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
685dfdaa8733814dd1a576aec0a0a735848384009dfBrian McKenna        if (ch == '$' || ch > 127) {
686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sprintf(cp, "_0%04x", ch);
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cp += 6;
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            switch (ch) {
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case '_':
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = '_';
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = '1';
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case ';':
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = '_';
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = '2';
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case '[':
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = '_';
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = '3';
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case '/':
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = '_';
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            default:
706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *cp++ = (char) ch;
707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *cp = '\0';
713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(utf16);
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return mangle;
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create the mangled form of the parameter types.
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic char* createMangledSignature(const DexProto* proto)
723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DexStringCache sigCache;
725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* interim;
726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* result;
727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dexStringCacheInit(&sigCache);
729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    interim = dexProtoGetParameterDescriptors(proto, &sigCache);
730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = mangleString(interim, strlen(interim));
731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dexStringCacheRelease(&sigCache);
732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (This is a dvmHashForeach callback.)
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Search for a matching method in this shared library.
74070318889578ab67943d6df29fedf09b11cfef015Andy McFadden *
74170318889578ab67943d6df29fedf09b11cfef015Andy McFadden * TODO: we may want to skip libraries for which JNI_OnLoad failed.
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic int findMethodInLib(void* vlib, void* vmethod)
744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const SharedLib* pLib = (const SharedLib*) vlib;
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* meth = (const Method*) vmethod;
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* preMangleCM = NULL;
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* mangleCM = NULL;
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* mangleSig = NULL;
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* mangleCMSig = NULL;
751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    void* func = NULL;
752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int len;
753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (meth->clazz->classLoader != pLib->classLoader) {
755dced79474902ffa57fbd48121eb794aad7d24ddcAndy McFadden        LOGV("+++ not scanning '%s' for '%s' (wrong CL)\n",
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pLib->pathName, meth->name);
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return 0;
758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGV("+++ scanning '%s' for '%s'\n", pLib->pathName, meth->name);
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * First, we try it without the signature.
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    preMangleCM =
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        createJniNameString(meth->clazz->descriptor, meth->name, &len);
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (preMangleCM == NULL)
767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    mangleCM = mangleString(preMangleCM, len);
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (mangleCM == NULL)
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    LOGV("+++ calling dlsym(%s)\n", mangleCM);
774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    func = dlsym(pLib->handle, mangleCM);
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (func == NULL) {
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mangleSig =
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            createMangledSignature(&meth->prototype);
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (mangleSig == NULL)
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mangleCMSig = (char*) malloc(strlen(mangleCM) + strlen(mangleSig) +3);
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (mangleCMSig == NULL)
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sprintf(mangleCMSig, "%s__%s", mangleCM, mangleSig);
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGV("+++ calling dlsym(%s)\n", mangleCMSig);
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        func = dlsym(pLib->handle, mangleCMSig);
789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (func != NULL) {
790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGV("Found '%s' with dlsym\n", mangleCMSig);
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGV("Found '%s' with dlsym\n", mangleCM);
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(preMangleCM);
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(mangleCM);
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(mangleSig);
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(mangleCMSig);
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return (int) func;
802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See if the requested method lives in any of the currently-loaded
806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * shared libraries.  We do this by checking each of them for the expected
807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * method signature.
808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void* lookupSharedLibMethod(const Method* method)
810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gDvm.nativeLibs == NULL) {
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("Unexpected init state: nativeLibs not ready\n");
813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmAbort();
814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return (void*) dvmHashForeach(gDvm.nativeLibs, findMethodInLib,
816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        (void*) method);
817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
818