@Override public void handleException(Exception e) { if (mIsDevSupportEnabled) { if (e instanceof JSException) { FLog.e(ReactConstants.TAG, "Exception in native call from JS", e); // TODO #11638796: convert the stack into something useful showNewError( e.getMessage() + "\n\n" + ((JSException) e).getStack(), new StackFrame[] {}, JSEXCEPTION_ERROR_COOKIE, ErrorType.JS); } else { showNewJavaError(e.getMessage(), e); } } else { mDefaultNativeModuleCallExceptionHandler.handleException(e); } }
private boolean renderFrameAndCache( int frameNumber, CloseableReference<Bitmap> bitmapReference, @BitmapAnimationBackend.FrameType int frameType) { // Check if the bitmap is valid if (!CloseableReference.isValid(bitmapReference)) { return false; } // Try to render the frame if (!mBitmapFrameRenderer.renderFrame(frameNumber, bitmapReference.get())) { return false; } FLog.v(TAG, "Frame %d ready.", mFrameNumber); // Cache the frame synchronized (mPendingFrameDecodeJobs) { mBitmapFrameCache.onFramePrepared(mFrameNumber, bitmapReference, frameType); } return true; }
protected void onCreate(Bundle savedInstanceState) { boolean needsOverlayPermission = false; if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Get permission to show redbox in dev builds. if (!Settings.canDrawOverlays(getContext())) { needsOverlayPermission = true; Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName())); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); ((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE); } } if (mMainComponentName != null && !needsOverlayPermission) { loadApp(mMainComponentName); } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); }
@Override public void initialize() { super.initialize(); getReactApplicationContext().addLifecycleEventListener(this); if (!hasBeenInitialized()) { // Make sure the SoLoaderShim is configured to use our loader for native libraries. // This code can be removed if using Fresco from Maven rather than from source SoLoaderShim.setHandler(new FrescoHandler()); if (mConfig == null) { mConfig = getDefaultConfig(getReactApplicationContext()); } Context context = getReactApplicationContext().getApplicationContext(); Fresco.initialize(context, mConfig); sHasBeenInitialized = true; } else if (mConfig != null) { FLog.w( ReactConstants.TAG, "Fresco has already been initialized with a different config. " + "The new Fresco configuration will be ignored!"); } mConfig = null; }
/** * Decreases the reference count of live object from the static map. Removes it if it's reference * count has become 0. * * @param value the value to remove. */ private static void removeLiveReference(Object value) { synchronized (sLiveObjects) { Integer count = sLiveObjects.get(value); if (count == null) { // Uh oh. FLog.wtf( "SharedReference", "No entry in sLiveObjects for value of type %s", value.getClass()); } else if (count == 1) { sLiveObjects.remove(value); } else { sLiveObjects.put(value, count - 1); } } }
/** * Clears the database. */ @ReactMethod public void clear(final Callback callback) { new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) { @Override protected void doInBackgroundGuarded(Void... params) { if (!mReactDatabaseSupplier.ensureDatabase()) { callback.invoke(AsyncStorageErrorUtil.getDBError(null)); return; } try { mReactDatabaseSupplier.clear(); callback.invoke(); } catch (Exception e) { FLog.w(ReactConstants.TAG, e.getMessage(), e); callback.invoke(AsyncStorageErrorUtil.getError(null, e.getMessage())); } } }.execute(); }
@Override public void run() { try { Runnable runnable = mWorkQueue.poll(); if (runnable != null) { runnable.run(); } else { // It is possible that a new worker was started before a previously started worker // de-queued its work item. FLog.v(TAG, "%s: Worker has nothing to run", mName); } } finally { int workers = mPendingWorkers.decrementAndGet(); if (!mWorkQueue.isEmpty()) { startWorkerIfNeeded(); } else { FLog.v(TAG, "%s: worker finished; %d workers left", mName, workers); } } }
@Override public double getTrimRatio(MemoryTrimType trimType) { switch (trimType) { case OnCloseToDalvikHeapLimit: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio(); } else { // On pre-lollipop versions we keep bitmaps on the native heap, so no need to trim here // as it wouldn't help Dalvik heap anyway. return 0; } case OnAppBackgrounded: case OnSystemLowMemoryWhileAppInForeground: case OnSystemLowMemoryWhileAppInBackground: return 1; default: FLog.wtf(TAG, "unknown trim type: %s", trimType); return 0; } }
public int resolveRootTagFromReactTag(int reactTag) { if (mShadowNodeRegistry.isRootNode(reactTag)) { return reactTag; } ReactShadowNode node = resolveShadowNode(reactTag); int rootTag = 0; if (node != null) { rootTag = node.getRootNode().getReactTag(); } else { FLog.w( ReactConstants.TAG, "Warning : attempted to resolve a non-existent react shadow node. reactTag=" + reactTag); } return rootTag; }
/** * Parse a DebugServerException from the server json string. * @param str json string returned by the debug server * @return A DebugServerException or null if the string is not of proper form. */ @Nullable public static DebugServerException parse(String str) { if (TextUtils.isEmpty(str)) { return null; } try { JSONObject jsonObject = new JSONObject(str); String fullFileName = jsonObject.getString("filename"); return new DebugServerException( jsonObject.getString("description"), shortenFileName(fullFileName), jsonObject.getInt("lineNumber"), jsonObject.getInt("column")); } catch (JSONException e) { // I'm not sure how strict this format is for returned errors, or what other errors there can // be, so this may end up being spammy. Can remove it later if necessary. FLog.w(ReactConstants.TAG, "Could not parse DebugServerException from: " + str, e); return null; } }
public void updateShadowNodeProp( ReactShadowNode nodeToUpdate, ReactStylesDiffMap props) { try { if (mIndex == null) { SHADOW_ARGS[0] = extractProperty(props); mSetter.invoke(nodeToUpdate, SHADOW_ARGS); Arrays.fill(SHADOW_ARGS, null); } else { SHADOW_GROUP_ARGS[0] = mIndex; SHADOW_GROUP_ARGS[1] = extractProperty(props); mSetter.invoke(nodeToUpdate, SHADOW_GROUP_ARGS); Arrays.fill(SHADOW_GROUP_ARGS, null); } } catch (Throwable t) { FLog.e(ViewManager.class, "Error while updating prop " + mPropName, t); throw new JSApplicationIllegalArgumentException("Error while updating property '" + mPropName + "' in shadow node of type: " + nodeToUpdate.getViewClass(), t); } }
private void reconnect() { if (mClosed) { throw new IllegalStateException("Can't reconnect closed client"); } if (!mSuppressConnectionErrors) { FLog.w(TAG, "Couldn't connect to \"" + mUrl + "\", will silently retry"); mSuppressConnectionErrors = true; } mHandler.postDelayed( new Runnable() { @Override public void run() { delayedReconnect(); } }, RECONNECT_DELAY_MS); }
@ReactMethod public void setStyle(final String style) { final Activity activity = getCurrentActivity(); if (activity == null) { FLog.w(ReactConstants.TAG, "StatusBarModule: Ignored status bar change, current activity is null."); return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { UiThreadUtil.runOnUiThread( new Runnable() { @TargetApi(Build.VERSION_CODES.M) @Override public void run() { View decorView = activity.getWindow().getDecorView(); decorView.setSystemUiVisibility( style.equals("dark-content") ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0); } } ); } }
public String getDebugServerHost() { // Check host setting first. If empty try to detect emulator type and use default // hostname for those String hostFromSettings = mPreferences.getString(PREFS_DEBUG_SERVER_HOST_KEY, null); if (!TextUtils.isEmpty(hostFromSettings)) { return Assertions.assertNotNull(hostFromSettings); } String host = AndroidInfoHelpers.getServerHost(); if (host.equals(AndroidInfoHelpers.DEVICE_LOCALHOST)) { FLog.w( TAG, "You seem to be running on device. Run 'adb reverse tcp:8081 tcp:8081' " + "to forward the debug server's port to the device."); } return host; }
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.startsWith("http://") || url.startsWith("https://") || url.startsWith("file://")) { return false; } else { try { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); view.getContext().startActivity(intent); } catch (ActivityNotFoundException e) { FLog.w(ReactConstants.TAG, "activity not found to handle uri scheme for: " + url, e); } return true; } }
@Override public synchronized void onRequestStart( ImageRequest request, Object callerContextObject, String requestId, boolean isPrefetch) { if (FLog.isLoggable(FLog.VERBOSE)) { FLog.v( TAG, "time %d: onRequestSubmit: {requestId: %s, callerContext: %s, isPrefetch: %b}", getTime(), requestId, callerContextObject, isPrefetch); mRequestStartTimeMap.put(requestId, getTime()); } }
@Override public void setElevation(ReactDrawerLayout view, float elevation) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Facebook is using an older version of the support lib internally that doesn't support // setDrawerElevation so we invoke it using reflection. // TODO: Call the method directly when this is no longer needed. try { Method method = ReactDrawerLayout.class.getMethod("setDrawerElevation", float.class); method.invoke(view, PixelUtil.toPixelFromDIP(elevation)); } catch (Exception ex) { FLog.w( ReactConstants.TAG, "setDrawerElevation is not available in this version of the support lib.", ex); } } }
@Override public synchronized void onProducerFinishWithSuccess( String requestId, String producerName, @Nullable Map<String, String> extraMap) { if (FLog.isLoggable(FLog.VERBOSE)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); Long startTime = mProducerStartTimeMap.remove(mapKey); long currentTime = getTime(); FLog.v( TAG, "time %d: onProducerFinishWithSuccess: " + "{requestId: %s, producer: %s, elapsedTime: %d ms, extraMap: %s}", currentTime, requestId, producerName, getElapsedTime(startTime, currentTime), extraMap); } }
@Override public synchronized void onProducerEvent( String requestId, String producerName, String producerEventName) { if (FLog.isLoggable(FLog.VERBOSE)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); Long startTime = mProducerStartTimeMap.get(mapKey); long currentTime = getTime(); FLog.v( TAG, "time %d: onProducerEvent: {requestId: %s, stage: %s, eventName: %s; elapsedTime: %d ms}", getTime(), requestId, producerName, producerEventName, getElapsedTime(startTime, currentTime)); } }
@Override public synchronized void onUltimateProducerReached( String requestId, String producerName, boolean successful) { if (FLog.isLoggable(FLog.VERBOSE)) { Pair<String, String> mapKey = Pair.create(requestId, producerName); Long startTime = mProducerStartTimeMap.remove(mapKey); long currentTime = getTime(); FLog.v( TAG, "time %d: onUltimateProducerReached: " + "{requestId: %s, producer: %s, elapsedTime: %d ms, success: %b}", currentTime, requestId, producerName, getElapsedTime(startTime, currentTime), successful); } }
@Override public synchronized void onRequestSuccess( ImageRequest request, String requestId, boolean isPrefetch) { if (FLog.isLoggable(FLog.VERBOSE)) { Long startTime = mRequestStartTimeMap.remove(requestId); long currentTime = getTime(); FLog.v( TAG, "time %d: onRequestSuccess: {requestId: %s, elapsedTime: %d ms}", currentTime, requestId, getElapsedTime(startTime, currentTime)); } }
@Override public Task<MediaVariations> getCachedVariants( final String mediaId, final MediaVariations.Builder mediaVariationsBuilder) { try { return Task.call( new Callable<MediaVariations>() { @Override public MediaVariations call() throws Exception { return getCachedVariantsSync(mediaId, mediaVariationsBuilder); } }, mReadExecutor); } catch (Exception exception) { FLog.w(TAG, exception, "Failed to schedule query task for %s", mediaId); return Task.forError(exception); } }
/** * @param key * @return value associated with given key or null if no value is associated */ public synchronized EncodedImage get(final CacheKey key) { Preconditions.checkNotNull(key); EncodedImage storedEncodedImage = mMap.get(key); if (storedEncodedImage != null) { synchronized (storedEncodedImage) { if (!EncodedImage.isValid(storedEncodedImage)) { // Reference is not valid, this means that someone cleared reference while it was still in // use. Log error // TODO: 3697790 mMap.remove(key); FLog.w( TAG, "Found closed reference %d for key %s (%d)", System.identityHashCode(storedEncodedImage), key.getUriString(), System.identityHashCode(key)); return null; } storedEncodedImage = EncodedImage.cloneOrNull(storedEncodedImage); } } return storedEncodedImage; }
/** * Determine if an valid entry for the key exists in the staging area. */ public synchronized boolean containsKey(CacheKey key) { Preconditions.checkNotNull(key); if (!mMap.containsKey(key)) { return false; } EncodedImage storedEncodedImage = mMap.get(key); synchronized (storedEncodedImage) { if (!EncodedImage.isValid(storedEncodedImage)) { // Reference is not valid, this means that someone cleared reference while it was still in // use. Log error // TODO: 3697790 mMap.remove(key); FLog.w( TAG, "Found closed reference %d for key %s (%d)", System.identityHashCode(storedEncodedImage), key.getUriString(), System.identityHashCode(key)); return false; } return true; } }
/** * Performs key-value loop up in staging area and file cache. * Any error manifests itself as a miss, i.e. returns false. * @param key * @return true if the image is found in staging area or File cache, false if not found */ private boolean checkInStagingAreaAndFileCache(final CacheKey key) { EncodedImage result = mStagingArea.get(key); if (result != null) { result.close(); FLog.v(TAG, "Found image for %s in staging area", key.getUriString()); mImageCacheStatsTracker.onStagingAreaHit(key); return true; } else { FLog.v(TAG, "Did not find image for %s in staging area", key.getUriString()); mImageCacheStatsTracker.onStagingAreaMiss(); try { return mFileCache.hasKey(key); } catch (Exception exception) { return false; } } }
private void dispatchCancelEvent(MotionEvent androidEvent, EventDispatcher eventDispatcher) { // This means the gesture has already ended, via some other CANCEL or UP event. This is not // expected to happen very often as it would mean some child View has decided to intercept the // touch stream and start a native gesture only upon receiving the UP/CANCEL event. if (mTargetTag == -1) { FLog.w( ReactConstants.TAG, "Can't cancel already finished gesture. Is a child View trying to start a gesture from " + "an UP/CANCEL event?"); return; } Assertions.assertCondition( !mChildIsHandlingNativeGesture, "Expected to not have already sent a cancel for this gesture"); Assertions.assertNotNull(eventDispatcher).dispatchEvent( TouchEvent.obtain( mTargetTag, TouchEventType.CANCEL, androidEvent, mGestureStartTime, mTargetCoordinates[0], mTargetCoordinates[1], mTouchEventCoalescingKeyHelper)); }
@Override public void run() { // clean up files that are past their expiry date synchronized (mOpenFiles) { Iterator<TtlFileInputStream> i = mOpenFiles.values().iterator(); while (i.hasNext()) { TtlFileInputStream stream = i.next(); if (stream.expiredTtl()) { i.remove(); try { stream.close(); } catch (IOException e) { FLog.e( TAG, "closing expired file failed: " + e.toString()); } } } if (!mOpenFiles.isEmpty()) { mHandler.postDelayed(this, FILE_TTL); } } }
public void linkBridge() { if (messagingEnabled) { if (ReactBuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // See isNative in lodash String testPostMessageNative = "String(window.postMessage) === String(Object.hasOwnProperty).replace('hasOwnProperty', 'postMessage')"; evaluateJavascript(testPostMessageNative, new ValueCallback<String>() { @Override public void onReceiveValue(String value) { if (value.equals("true")) { FLog.w(ReactConstants.TAG, "Setting onMessage on a WebView overrides existing values of window.postMessage, but a previous value was defined"); } } }); } loadUrl("javascript:(" + "window.originalPostMessage = window.postMessage," + "window.postMessage = function(data) {" + BRIDGE_NAME + ".postMessage(String(data));" + "}" + ")"); } }
@Override public void callFunction( ExecutorToken executorToken, final String module, final String method, final NativeArray arguments) { if (mDestroyed) { FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed."); return; } if (!mAcceptCalls) { // Most of the time the instance is initialized and we don't need to acquire the lock synchronized (mJSCallsPendingInitLock) { if (!mAcceptCalls) { mJSCallsPendingInit.add(new PendingJSCall(executorToken, module, method, arguments)); return; } } } jniCallJSFunction(executorToken, module, method, arguments); }
@Override protected Void doInBackground(String... jsonData) { try { String jscProfileUrl = Uri.parse(mSourceUrl).buildUpon() .path("/jsc-profile") .query(null) .build() .toString(); OkHttpClient client = new OkHttpClient(); for (String json: jsonData) { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder().url(jscProfileUrl).post(body).build(); client.newCall(request).execute(); } } catch (IOException e) { FLog.e(ReactConstants.TAG, "Failed not talk to server", e); } return null; }
@Override protected Void doInBackground(String... clipBoardString) { try { String sendClipBoardUrl = Uri.parse(mDevSupportManager.getSourceUrl()).buildUpon() .path("/copy-to-clipboard") .query(null) .build() .toString(); for (String string: clipBoardString) { OkHttpClient client = new OkHttpClient(); RequestBody body = RequestBody.create(null, string); Request request = new Request.Builder().url(sendClipBoardUrl).post(body).build(); client.newCall(request).execute(); } } catch (Exception e) { FLog.e(ReactConstants.TAG, "Could not copy to the host clipboard", e); } return null; }
private void drawOutput() { if (mSurface == null || !mSurface.isValid()) { markChildrenUpdatesSeen(this); return; } try { Canvas canvas = mSurface.lockCanvas(null); canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); Paint paint = new Paint(); for (int i = 0; i < getChildCount(); i++) { ARTVirtualNode child = (ARTVirtualNode) getChildAt(i); child.draw(canvas, paint, 1f); child.markUpdateSeen(); } if (mSurface == null) { return; } mSurface.unlockCanvasAndPost(canvas); } catch (IllegalArgumentException | IllegalStateException e) { FLog.e(ReactConstants.TAG, e.getClass().getSimpleName() + " in Surface.unlockCanvasAndPost"); } }
@ReactMethod public void close(int code, String reason, int id) { WebSocket client = mWebSocketConnections.get(id); if (client == null) { // WebSocket is already closed // Don't do anything, mirror the behaviour on web return; } try { client.close(code, reason); mWebSocketConnections.remove(id); } catch (Exception e) { FLog.e( ReactConstants.TAG, "Could not close WebSocket connection for id " + id, e); } }
/** * Sets up {@link #mPaint} according to the props set on a shadow view. Returns {@code true} * if the fill should be drawn, {@code false} if not. */ protected boolean setupFillPaint(Paint paint, float opacity) { if (mFillColor != null && mFillColor.length > 0) { paint.reset(); paint.setFlags(Paint.ANTI_ALIAS_FLAG); paint.setStyle(Paint.Style.FILL); int colorType = (int) mFillColor[0]; switch (colorType) { case 0: paint.setARGB( (int) (mFillColor.length > 4 ? mFillColor[4] * opacity * 255 : opacity * 255), (int) (mFillColor[1] * 255), (int) (mFillColor[2] * 255), (int) (mFillColor[3] * 255)); break; default: // TODO(6352048): Support gradients etc. FLog.w(ReactConstants.TAG, "ART: Color type " + colorType + " not supported!"); } return true; } return false; }
private WebsocketJavaScriptExecutor.JSExecutorConnectCallback getExecutorConnectCallback( final SimpleSettableFuture<Boolean> future) { return new WebsocketJavaScriptExecutor.JSExecutorConnectCallback() { @Override public void onSuccess() { future.set(true); mDevLoadingViewController.hide(); mDevLoadingViewVisible = false; } @Override public void onFailure(final Throwable cause) { mDevLoadingViewController.hide(); mDevLoadingViewVisible = false; FLog.e(ReactConstants.TAG, "Unable to connect to remote debugger", cause); future.setException( new IOException( mApplicationContext.getString(R.string.catalyst_remotedbg_error), cause)); } }; }
private CatalystInstanceImpl( final ReactQueueConfigurationSpec ReactQueueConfigurationSpec, final JavaScriptExecutor jsExecutor, final NativeModuleRegistry registry, final JavaScriptModuleRegistry jsModuleRegistry, final JSBundleLoader jsBundleLoader, NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) { FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge."); mHybridData = initHybrid(); mReactQueueConfiguration = ReactQueueConfigurationImpl.create( ReactQueueConfigurationSpec, new NativeExceptionHandler()); mBridgeIdleListeners = new CopyOnWriteArrayList<>(); mJavaRegistry = registry; mJSModuleRegistry = jsModuleRegistry; mJSBundleLoader = jsBundleLoader; mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler; mNativeModulesQueueThread = mReactQueueConfiguration.getNativeModulesQueueThread(); mTraceListener = new JSProfilerTraceListener(this); FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge before initializeBridge"); initializeBridge( new BridgeCallback(this), jsExecutor, mReactQueueConfiguration.getJSQueueThread(), mNativeModulesQueueThread, mJavaRegistry.getJavaModules(this), mJavaRegistry.getCxxModules()); FLog.w(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge"); mMainExecutorToken = getMainExecutorToken(); }