Skip to content

Commit c2e3be5

Browse files
gcondraAndroid (Google) Code Review
authored andcommitted
Merge "DO NOT MERGE Control access to inherited methods of jsinterface objects" into jb-dev
2 parents a22000d + 534a67c commit c2e3be5

File tree

5 files changed

+125
-20
lines changed

5 files changed

+125
-20
lines changed

core/java/android/webkit/AccessibilityInjector.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import java.net.URI;
3636
import java.net.URISyntaxException;
37+
import java.util.HashMap;
3738
import java.util.Iterator;
3839
import java.util.List;
3940
import java.util.concurrent.atomic.AtomicInteger;
@@ -53,7 +54,7 @@ class AccessibilityInjector {
5354
private final WebView mWebView;
5455

5556
// The Java objects that are exposed to JavaScript.
56-
private TextToSpeech mTextToSpeech;
57+
private TextToSpeechWrapper mTextToSpeech;
5758
private CallbackHandler mCallback;
5859

5960
// Lazily loaded helper objects.
@@ -349,11 +350,8 @@ private void addTtsApis() {
349350
if (mTextToSpeech != null) {
350351
return;
351352
}
352-
353-
final String pkgName = mContext.getPackageName();
354-
355-
mTextToSpeech = new TextToSpeech(mContext, null, null, pkgName + ".**webview**", true);
356-
mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE);
353+
mTextToSpeech = new TextToSpeechWrapper(mContext);
354+
mWebViewClassic.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE, false);
357355
}
358356

359357
/**
@@ -377,7 +375,7 @@ private void addCallbackApis() {
377375
}
378376

379377
mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE);
380-
mWebView.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE);
378+
mWebViewClassic.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE, false);
381379
}
382380

383381
private void removeCallbackApis() {
@@ -504,9 +502,45 @@ private boolean sendActionToAndroidVox(int action, Bundle arguments) {
504502

505503
final String jsonString = mAccessibilityJSONObject.toString();
506504
final String jsCode = String.format(ACCESSIBILITY_ANDROIDVOX_TEMPLATE, jsonString);
505+
if (mCallback == null) return false;
507506
return mCallback.performAction(mWebView, jsCode);
508507
}
509508

509+
/**
510+
* Used to protect the TextToSpeech class, only exposing the methods we want to expose.
511+
*/
512+
private static class TextToSpeechWrapper {
513+
private TextToSpeech mTextToSpeech;
514+
515+
public TextToSpeechWrapper(Context context) {
516+
final String pkgName = context.getPackageName();
517+
mTextToSpeech = new TextToSpeech(context, null, null, pkgName + ".**webview**", true);
518+
}
519+
520+
@JavascriptInterface
521+
@SuppressWarnings("unused")
522+
public boolean isSpeaking() {
523+
return mTextToSpeech.isSpeaking();
524+
}
525+
526+
@JavascriptInterface
527+
@SuppressWarnings("unused")
528+
public int speak(String text, int queueMode, HashMap<String, String> params) {
529+
return mTextToSpeech.speak(text, queueMode, params);
530+
}
531+
532+
@JavascriptInterface
533+
@SuppressWarnings("unused")
534+
public int stop() {
535+
return mTextToSpeech.stop();
536+
}
537+
538+
@SuppressWarnings("unused")
539+
protected void shutdown() {
540+
mTextToSpeech.shutdown();
541+
}
542+
}
543+
510544
/**
511545
* Exposes result interface to JavaScript.
512546
*/
@@ -603,6 +637,7 @@ private boolean waitForResultTimedLocked(int resultId) {
603637
* @param id The result id of the request as a {@link String}.
604638
* @param result The result of the request as a {@link String}.
605639
*/
640+
@JavascriptInterface
606641
@SuppressWarnings("unused")
607642
public void onResult(String id, String result) {
608643
final long resultId;

core/java/android/webkit/BrowserFrame.java

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

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

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

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

242251
mSettings = settings;
@@ -590,15 +599,34 @@ 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+
*/
617+
private void addJavaScriptObjects(Map<String, Object> javascriptInterfaces) {
618+
619+
if (javascriptInterfaces == null) return;
620+
Iterator<String> iter = javascriptInterfaces.keySet().iterator();
621+
while (iter.hasNext()) {
622+
String interfaceName = iter.next();
623+
Object object = javascriptInterfaces.get(interfaceName);
624+
if (object != null) {
625+
mJavaScriptObjects.put(interfaceName, new JSObject(object, false));
626+
}
627+
}
628+
}
629+
602630
/**
603631
* This method is called by WebCore to check whether application
604632
* wants to hijack url loading
@@ -616,11 +644,11 @@ public boolean handleUrl(String url) {
616644
}
617645
}
618646

619-
public void addJavascriptInterface(Object obj, String interfaceName) {
647+
public void addJavascriptInterface(Object obj, String interfaceName,
648+
boolean requireAnnotation) {
620649
assert obj != null;
621650
removeJavascriptInterface(interfaceName);
622-
623-
mJavaScriptObjects.put(interfaceName, obj);
651+
mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation));
624652
}
625653

626654
public void removeJavascriptInterface(String interfaceName) {
@@ -1246,7 +1274,7 @@ private native void nativeCallPolicyFunction(int policyFunction,
12461274
* Add a javascript interface to the main frame.
12471275
*/
12481276
private native void nativeAddJavascriptInterface(int nativeFramePointer,
1249-
Object obj, String interfaceName);
1277+
Object obj, String interfaceName, boolean requireAnnotation);
12501278

12511279
public native void clearCache();
12521280

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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.
26+
*
27+
* @hide
28+
*/
29+
@SuppressWarnings("javadoc")
30+
@Retention(RetentionPolicy.RUNTIME)
31+
@Target({ElementType.METHOD})
32+
public @interface JavascriptInterface {
33+
}

core/java/android/webkit/WebViewClassic.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4085,12 +4085,20 @@ public void documentAsText(Message callback) {
40854085
*/
40864086
@Override
40874087
public void addJavascriptInterface(Object object, String name) {
4088+
addJavascriptInterface(object, name, false);
4089+
}
4090+
4091+
/**
4092+
* @hide
4093+
*/
4094+
public void addJavascriptInterface(Object object, String name, boolean requireAnnotation) {
40884095
if (object == null) {
40894096
return;
40904097
}
40914098
WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
40924099
arg.mObject = object;
40934100
arg.mInterfaceName = name;
4101+
arg.mRequireAnnotation = requireAnnotation;
40944102
mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
40954103
}
40964104

core/java/android/webkit/WebViewCore.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ static class BaseUrlData {
839839
static class JSInterfaceData {
840840
Object mObject;
841841
String mInterfaceName;
842+
boolean mRequireAnnotation;
842843
}
843844

844845
static class JSKeyData {
@@ -1508,7 +1509,7 @@ public void handleMessage(Message msg) {
15081509
case ADD_JS_INTERFACE:
15091510
JSInterfaceData jsData = (JSInterfaceData) msg.obj;
15101511
mBrowserFrame.addJavascriptInterface(jsData.mObject,
1511-
jsData.mInterfaceName);
1512+
jsData.mInterfaceName, jsData.mRequireAnnotation);
15121513
break;
15131514

15141515
case REMOVE_JS_INTERFACE:

0 commit comments

Comments
 (0)