blob: a23d15b5c6e1466b19221c9c55eb6466c1c1dae2 [file] [log] [blame]
/*
* Copyright (C) 2015 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.
*/
package com.android.tools.idea.debug;
import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.openapi.diagnostic.Logger;
import com.sun.jdi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
/**
* {@link DynamicResourceIdResolver} can resolve a resource id to its name by invoking Resources.getResourceName()
* on all the Resources objects inside the target VM.
*/
public class DynamicResourceIdResolver implements ResourceIdResolver {
private static final Logger LOG = Logger.getInstance(DynamicResourceIdResolver.class);
public static final String ANDROID_CONTENT_RES_RESOURCES = "android.content.res.Resources";
private final EvaluationContext myContext;
private final ResourceIdResolver myDelegate;
public DynamicResourceIdResolver(@NotNull EvaluationContext context, @NotNull ResourceIdResolver delegate) {
myContext = context;
myDelegate = delegate;
}
@Nullable
@Override
public String getAndroidResourceName(int resId) {
String id = myDelegate.getAndroidResourceName(resId);
if (id != null) {
return id;
}
DebugProcess debugProcess = myContext.getDebugProcess();
VirtualMachineProxyImpl vmProxy = (VirtualMachineProxyImpl)debugProcess.getVirtualMachineProxy();
List<ReferenceType> classes = vmProxy.classesByName(ANDROID_CONTENT_RES_RESOURCES);
if (classes.isEmpty()) {
LOG.warn(ANDROID_CONTENT_RES_RESOURCES + " class not loaded?");
return null;
}
if (classes.size() != 1) {
LOG.warn("Expected a single Resource class loaded, but found " + classes.size());
}
ReferenceType resourcesClassType = classes.get(0);
Method getResourceNameMethod = DebuggerUtils.findMethod(resourcesClassType, "getResourceName", "(I)Ljava/lang/String;");
if (getResourceNameMethod == null) {
LOG.warn("Unable to locate getResourceName(int id) in class " + resourcesClassType.name());
return null;
}
List<ObjectReference> instances = resourcesClassType.instances(10);
if (instances.isEmpty()) {
LOG.warn("No instances of Resource class found");
return null;
}
List args = Collections.singletonList(DebuggerUtilsEx.createValue(vmProxy, "int", resId));
for (ObjectReference ref : instances) {
try {
Value value = debugProcess.invokeMethod(myContext, ref, getResourceNameMethod, args);
if (value instanceof StringReference) {
StringReference nameRef = (StringReference)value;
return nameRef.value();
}
}
catch (EvaluateException e) {
LOG.warn("Unexpected error while invoking Resources.getResourceName()", e);
// continue and try this on other object references
}
}
return null;
}
}