/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* java.security.AccessController
*/
#include "Dalvik.h"
#include "native/InternalNativePriv.h"
/*
* private static ProtectionDomain[] getStackDomains()
*
* Return an array of ProtectionDomain objects from the classes of the
* methods on the stack. Ignore reflection frames. Stop at the first
* privileged frame we see.
*/
static void Dalvik_java_security_AccessController_getStackDomains(
const u4* args, JValue* pResult)
{
UNUSED_PARAMETER(args);
const Method** methods = NULL;
int length;
/*
* Get an array with the stack trace in it.
*/
if (!dvmCreateStackTraceArray(dvmThreadSelf()->curFrame, &methods, &length))
{
LOGE("Failed to create stack trace array\n");
dvmThrowException("Ljava/lang/InternalError;", NULL);
RETURN_VOID();
}
//int i;
//LOGI("dvmCreateStackTraceArray results:\n");
//for (i = 0; i < length; i++)
// LOGI(" %2d: %s.%s\n", i, methods[i]->clazz->name, methods[i]->name);
/*
* Generate a list of ProtectionDomain objects from the frames that
* we're interested in. Skip the first two methods (this method, and
* the one that called us), and ignore reflection frames. Stop on the
* frame *after* the first privileged frame we see as we walk up.
*
* We create a new array, probably over-allocated, and fill in the
* stuff we want. We could also just run the list twice, but the
* costs of the per-frame tests could be more expensive than the
* second alloc. (We could also allocate it on the stack using C99
* array creation, but it's not guaranteed to fit.)
*
* The array we return doesn't include null ProtectionDomain objects,
* so we skip those here.
*/
Object** subSet = (Object**) malloc((length-2) * sizeof(Object*));
if (subSet == NULL) {
LOGE("Failed to allocate subSet (length=%d)\n", length);
free(methods);
dvmThrowException("Ljava/lang/InternalError;", NULL);
RETURN_VOID();
}
int idx, subIdx = 0;
for (idx = 2; idx < length; idx++) {
const Method* meth = methods[idx];
Object* pd;
if (dvmIsReflectionMethod(meth))
continue;
if (dvmIsPrivilegedMethod(meth)) {
/* find nearest non-reflection frame; note we skip priv frame */
//LOGI("GSD priv frame at %s.%s\n", meth->clazz->name, meth->name);
while (++idx < length && dvmIsReflectionMethod(methods[idx]))
;
length = idx; // stomp length to end loop
meth = methods[idx];
}
/* get the pd object from the method's class */
assert(gDvm.offJavaLangClass_pd != 0);
pd = dvmGetFieldObject((Object*) meth->clazz,
gDvm.offJavaLangClass_pd);
//LOGI("FOUND '%s' pd=%p\n", meth->clazz->name, pd);
if (pd != NULL)
subSet[subIdx++] = pd;
}
//LOGI("subSet:\n");
//for (i = 0; i < subIdx; i++)
// LOGI(" %2d: %s\n", i, subSet[i]->clazz->name);
/*
* Create an array object to contain "subSet".
*/
ClassObject* pdArrayClass = NULL;
ArrayObject* domains = NULL;
pdArrayClass = dvmFindArrayClass("[Ljava/security/ProtectionDomain;", NULL);
if (pdArrayClass == NULL) {
LOGW("Unable to find ProtectionDomain class for array\n");
goto bail;
}
domains = dvmAllocArray(pdArrayClass, subIdx, kObjectArrayRefWidth,
ALLOC_DEFAULT);
if (domains == NULL) {
LOGW("Unable to allocate pd array (%d elems)\n", subIdx);
goto bail;
}
/* copy the ProtectionDomain objects out */
memcpy(domains->contents, subSet, subIdx * sizeof(Object *));
dvmWriteBarrierArray(domains, 0, subIdx);
bail:
free(subSet);
free(methods);
dvmReleaseTrackedAlloc((Object*) domains, NULL);
RETURN_PTR(domains);
}
const DalvikNativeMethod dvm_java_security_AccessController[] = {
{ "getStackDomains", "()[Ljava/security/ProtectionDomain;",
Dalvik_java_security_AccessController_getStackDomains },
{ NULL, NULL, NULL },
};