Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2e3be5a authored by Geremy Condra's avatar Geremy Condra Committed by Android (Google) Code Review
Browse files

Merge "DO NOT MERGE Control access to inherited methods of jsinterface objects" into jb-dev

parents a22000d2 534a67c5
Loading
Loading
Loading
Loading
+42 −7
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import org.json.JSONObject;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -53,7 +54,7 @@ class AccessibilityInjector {
    private final WebView mWebView;

    // The Java objects that are exposed to JavaScript.
    private TextToSpeech mTextToSpeech;
    private TextToSpeechWrapper mTextToSpeech;
    private CallbackHandler mCallback;

    // Lazily loaded helper objects.
@@ -349,11 +350,8 @@ class AccessibilityInjector {
        if (mTextToSpeech != null) {
            return;
        }

        final String pkgName = mContext.getPackageName();

        mTextToSpeech = new TextToSpeech(mContext, null, null, pkgName + ".**webview**", true);
        mWebView.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE);
        mTextToSpeech = new TextToSpeechWrapper(mContext);
        mWebViewClassic.addJavascriptInterface(mTextToSpeech, ALIAS_TTS_JS_INTERFACE, false);
    }

    /**
@@ -377,7 +375,7 @@ class AccessibilityInjector {
        }

        mCallback = new CallbackHandler(ALIAS_TRAVERSAL_JS_INTERFACE);
        mWebView.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE);
        mWebViewClassic.addJavascriptInterface(mCallback, ALIAS_TRAVERSAL_JS_INTERFACE, false);
    }

    private void removeCallbackApis() {
@@ -504,9 +502,45 @@ class AccessibilityInjector {

        final String jsonString = mAccessibilityJSONObject.toString();
        final String jsCode = String.format(ACCESSIBILITY_ANDROIDVOX_TEMPLATE, jsonString);
        if (mCallback == null) return false;
        return mCallback.performAction(mWebView, jsCode);
    }

    /**
     * Used to protect the TextToSpeech class, only exposing the methods we want to expose.
     */
    private static class TextToSpeechWrapper {
        private TextToSpeech mTextToSpeech;

        public TextToSpeechWrapper(Context context) {
            final String pkgName = context.getPackageName();
            mTextToSpeech = new TextToSpeech(context, null, null, pkgName + ".**webview**", true);
        }

        @JavascriptInterface
        @SuppressWarnings("unused")
        public boolean isSpeaking() {
            return mTextToSpeech.isSpeaking();
        }

        @JavascriptInterface
        @SuppressWarnings("unused")
        public int speak(String text, int queueMode, HashMap<String, String> params) {
            return mTextToSpeech.speak(text, queueMode, params);
        }

        @JavascriptInterface
        @SuppressWarnings("unused")
        public int stop() {
            return mTextToSpeech.stop();
        }

        @SuppressWarnings("unused")
        protected void shutdown() {
            mTextToSpeech.shutdown();
        }
    }

    /**
     * Exposes result interface to JavaScript.
     */
@@ -603,6 +637,7 @@ class AccessibilityInjector {
         * @param id The result id of the request as a {@link String}.
         * @param result The result of the request as a {@link String}.
         */
        @JavascriptInterface
        @SuppressWarnings("unused")
        public void onResult(String id, String result) {
            final long resultId;
+40 −12
Original line number Diff line number Diff line
@@ -88,8 +88,19 @@ class BrowserFrame extends Handler {
    // Is this frame the main frame?
    private boolean mIsMainFrame;

    // Javascript interface object
    private class JSObject {
        Object object;
        boolean requireAnnotation;

        public JSObject(Object object, boolean requireAnnotation) {
            this.object = object;
            this.requireAnnotation = requireAnnotation;
        }
    }

    // Attached Javascript interfaces
    private Map<String, Object> mJavaScriptObjects;
    private Map<String, JSObject> mJavaScriptObjects;
    private Set<Object> mRemovedJavaScriptObjects;

    // Key store handler when Chromium HTTP stack is used.
@@ -233,10 +244,8 @@ class BrowserFrame extends Handler {
        }
        sConfigCallback.addHandler(this);

        mJavaScriptObjects = javascriptInterfaces;
        if (mJavaScriptObjects == null) {
            mJavaScriptObjects = new HashMap<String, Object>();
        }
        mJavaScriptObjects = new HashMap<String, JSObject>();
        addJavaScriptObjects(javascriptInterfaces);
        mRemovedJavaScriptObjects = new HashSet<Object>();

        mSettings = settings;
@@ -590,15 +599,34 @@ class BrowserFrame extends Handler {
        Iterator<String> iter = mJavaScriptObjects.keySet().iterator();
        while (iter.hasNext())  {
            String interfaceName = iter.next();
            Object object = mJavaScriptObjects.get(interfaceName);
            if (object != null) {
            JSObject jsobject = mJavaScriptObjects.get(interfaceName);
            if (jsobject != null && jsobject.object != null) {
                nativeAddJavascriptInterface(nativeFramePointer,
                        mJavaScriptObjects.get(interfaceName), interfaceName);
                        jsobject.object, interfaceName, jsobject.requireAnnotation);
            }
        }
        mRemovedJavaScriptObjects.clear();
    }

    /*
     * Add javascript objects to the internal list of objects. The default behavior
     * is to allow access to inherited methods (no annotation needed). This is only
     * used when js objects are passed through a constructor (via a hidden constructor).
     *
     */
    private void addJavaScriptObjects(Map<String, Object> javascriptInterfaces) {

        if (javascriptInterfaces == null) return;
        Iterator<String> iter = javascriptInterfaces.keySet().iterator();
        while (iter.hasNext())  {
            String interfaceName = iter.next();
            Object object = javascriptInterfaces.get(interfaceName);
            if (object != null) {
                mJavaScriptObjects.put(interfaceName, new JSObject(object, false));
            }
        }
    }

    /**
     * This method is called by WebCore to check whether application
     * wants to hijack url loading
@@ -616,11 +644,11 @@ class BrowserFrame extends Handler {
        }
    }

    public void addJavascriptInterface(Object obj, String interfaceName) {
    public void addJavascriptInterface(Object obj, String interfaceName,
            boolean requireAnnotation) {
        assert obj != null;
        removeJavascriptInterface(interfaceName);

        mJavaScriptObjects.put(interfaceName, obj);
        mJavaScriptObjects.put(interfaceName, new JSObject(obj, requireAnnotation));
    }

    public void removeJavascriptInterface(String interfaceName) {
@@ -1246,7 +1274,7 @@ class BrowserFrame extends Handler {
     * Add a javascript interface to the main frame.
     */
    private native void nativeAddJavascriptInterface(int nativeFramePointer,
            Object obj, String interfaceName);
            Object obj, String interfaceName, boolean requireAnnotation);

    public native void clearCache();

+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 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 android.webkit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation that allows exposing methods to JavaScript.
 *
 * @hide
 */
@SuppressWarnings("javadoc")
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface JavascriptInterface {
}
 No newline at end of file
+8 −0
Original line number Diff line number Diff line
@@ -4085,12 +4085,20 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
     */
    @Override
    public void addJavascriptInterface(Object object, String name) {
        addJavascriptInterface(object, name, false);
    }

    /**
     * @hide
     */
    public void addJavascriptInterface(Object object, String name, boolean requireAnnotation) {
        if (object == null) {
            return;
        }
        WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
        arg.mObject = object;
        arg.mInterfaceName = name;
        arg.mRequireAnnotation = requireAnnotation;
        mWebViewCore.sendMessage(EventHub.ADD_JS_INTERFACE, arg);
    }

+2 −1
Original line number Diff line number Diff line
@@ -839,6 +839,7 @@ public final class WebViewCore {
    static class JSInterfaceData {
        Object mObject;
        String mInterfaceName;
        boolean mRequireAnnotation;
    }

    static class JSKeyData {
@@ -1508,7 +1509,7 @@ public final class WebViewCore {
                        case ADD_JS_INTERFACE:
                            JSInterfaceData jsData = (JSInterfaceData) msg.obj;
                            mBrowserFrame.addJavascriptInterface(jsData.mObject,
                                    jsData.mInterfaceName);
                                    jsData.mInterfaceName, jsData.mRequireAnnotation);
                            break;

                        case REMOVE_JS_INTERFACE: