Skip to content

Commit 94740e6

Browse files
author
Selim Gurun
committed
Control access to inherited methods of jsinterface objects
Bug: 7073422 Create the plumbing to use an annotation to allow access to inherited methods of jsinterface objects. The default webview behavior has not changed yet. However internally an a flag is introduced to restrict javascript access to methods that have an annotation. Change-Id: I41927248e6bc4b09d17c0707c60fe5e6ab681e66
1 parent bdf8fa0 commit 94740e6

File tree

5 files changed

+87
-13
lines changed

5 files changed

+87
-13
lines changed

core/java/android/webkit/BrowserFrame.java

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,19 @@ class BrowserFrame extends Handler {
8989
// Is this frame the main frame?
9090
private boolean mIsMainFrame;
9191

92+
// Javascript interface object
93+
private class JSObject {
94+
Object object;
95+
boolean requireAnnotation;
96+
97+
public JSObject(Object object, boolean requireAnnotation) {
98+
this.object = object;
99+
this.requireAnnotation = requireAnnotation;
100+
}
101+
}
102+
92103
// Attached Javascript interfaces
93-
private Map<String, Object> mJavaScriptObjects;
104+
private Map<String, JSObject> mJavaScriptObjects;
94105
private Set<Object> mRemovedJavaScriptObjects;
95106

96107
// Key store handler when Chromium HTTP stack is used.
@@ -234,10 +245,8 @@ public BrowserFrame(Context context, WebViewCore w, CallbackProxy proxy,
234245
}
235246
sConfigCallback.addHandler(this);
236247

237-
mJavaScriptObjects = javascriptInterfaces;
238-
if (mJavaScriptObjects == null) {
239-
mJavaScriptObjects = new HashMap<String, Object>();
240-
}
248+
mJavaScriptObjects = new HashMap<String, JSObject>();
249+
addJavaScriptObjects(javascriptInterfaces);
241250
mRemovedJavaScriptObjects = new HashSet<Object>();
242251

243252
mSettings = settings;
@@ -590,15 +599,36 @@ private void windowObjectCleared(int nativeFramePointer) {
590599
Iterator<String> iter = mJavaScriptObjects.keySet().iterator();
591600
while (iter.hasNext()) {
592601
String interfaceName = iter.next();
593-
Object object = mJavaScriptObjects.get(interfaceName);
594-
if (object != null) {
602+
JSObject jsobject = mJavaScriptObjects.get(interfaceName);
603+
if (jsobject != null && jsobject.object != null) {
595604
nativeAddJavascriptInterface(nativeFramePointer,
596-
mJavaScriptObjects.get(interfaceName), interfaceName);
605+
jsobject.object, interfaceName, jsobject.requireAnnotation);
597606
}
598607
}
599608
mRemovedJavaScriptObjects.clear();
600609
}
601610

611+
/*
612+
* Add javascript objects to the internal list of objects. The default behavior
613+
* is to allow access to inherited methods (no annotation needed). This is only
614+
* used when js objects are passed through a constructor (via a hidden constructor).
615+
*
616+
* @TODO change the default behavior to be compatible with the public addjavascriptinterface
617+
*/
618+
private void addJavaScriptObjects(Map<String, Object> javascriptInterfaces) {
619+
620+
// TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above.
621+
if (javascriptInterfaces == null) return;
622+
Iterator<String> iter = javascriptInterfaces.keySet().iterator();
623+
while (iter.hasNext()) {
624+
String interfaceName = iter.next();
625+
Object object = javascriptInterfaces.get(interfaceName);
626+
if (object != null) {
627+
mJavaScriptObjects.put(interfaceName, new JSObject(object, false));
628+
}
629+
}
630+
}
631+
602632
/**
603633
* This method is called by WebCore to check whether application
604634
* wants to hijack url loading
@@ -616,11 +646,11 @@ public boolean handleUrl(String url) {
616646
}
617647
}
618648

619-
public void addJavascriptInterface(Object obj, String interfaceName) {
649+
public void addJavascriptInterface(Object obj, String interfaceName,
650+
boolean requireAnnotation) {
620651
assert obj != null;
621652
removeJavascriptInterface(interfaceName);
622-
623-
mJavaScriptObjects.put(interfaceName, obj);
653+
mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation));
624654
}
625655

626656
public void removeJavascriptInterface(String interfaceName) {
@@ -1245,7 +1275,7 @@ private native void nativeCallPolicyFunction(int policyFunction,
12451275
* Add a javascript interface to the main frame.
12461276
*/
12471277
private native void nativeAddJavascriptInterface(int nativeFramePointer,
1248-
Object obj, String interfaceName);
1278+
Object obj, String interfaceName, boolean requireAnnotation);
12491279

12501280
public native void clearCache();
12511281

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (C) 2012 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+
17+
package android.webkit;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Annotation that allows exposing methods to JavaScript. Starting from API level
26+
* {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1} and above, only methods explicitly
27+
* marked with this annotation are available to the Javascript code. See
28+
* {@link android.webkit.Webview#addJavaScriptInterface} for more information about it.
29+
*
30+
* @hide
31+
*/
32+
@SuppressWarnings("javadoc")
33+
@Retention(RetentionPolicy.RUNTIME)
34+
@Target({ElementType.METHOD})
35+
public @interface JavascriptInterface {
36+
}

core/java/android/webkit/WebView.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import android.graphics.Rect;
2727
import android.graphics.drawable.Drawable;
2828
import android.net.http.SslCertificate;
29+
import android.os.Build;
2930
import android.os.Bundle;
3031
import android.os.Looper;
3132
import android.os.Message;
@@ -1507,6 +1508,9 @@ public void setPictureListener(PictureListener listener) {
15071508
public void addJavascriptInterface(Object object, String name) {
15081509
checkThread();
15091510
mProvider.addJavascriptInterface(object, name);
1511+
// TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above. Don't forget to
1512+
// update the doc, set a link to annotation and unhide the annotation.
1513+
// also describe that fields of java objects are not accessible from JS.
15101514
}
15111515

15121516
/**

core/java/android/webkit/WebViewClassic.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4114,12 +4114,15 @@ public void documentAsText(Message callback) {
41144114
*/
41154115
@Override
41164116
public void addJavascriptInterface(Object object, String name) {
4117+
41174118
if (object == null) {
41184119
return;
41194120
}
41204121
WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
4122+
// TODO in a separate CL provide logic to enable annotations for API level JB_MR1 and above.
41214123
arg.mObject = object;
41224124
arg.mInterfaceName = name;
4125+
arg.mRequireAnnotation = false;
41234126
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
41244127
}
41254128

core/java/android/webkit/WebViewCore.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,7 @@ static class BaseUrlData {
824824
static class JSInterfaceData {
825825
Object mObject;
826826
String mInterfaceName;
827+
boolean mRequireAnnotation;
827828
}
828829

829830
static class JSKeyData {
@@ -1489,7 +1490,7 @@ public void handleMessage(Message msg) {
14891490
case ADD_JS_INTERFACE:
14901491
JSInterfaceData jsData = (JSInterfaceData) msg.obj;
14911492
mBrowserFrame.addJavascriptInterface(jsData.mObject,
1492-
jsData.mInterfaceName);
1493+
jsData.mInterfaceName, jsData.mRequireAnnotation);
14931494
break;
14941495

14951496
case REMOVE_JS_INTERFACE:

0 commit comments

Comments
 (0)