Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply Nullsafe FIXMEs for xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/devsupport/BundleDownloader.java #50065

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ public void onResponse(Call call, final Response response) throws IOException {
// Make sure the result is a multipart response and parse the boundary.
String contentType = response.header("content-type");
Pattern regex = Pattern.compile("multipart/mixed;.*boundary=\"([^\"]+)\"");
// NULLSAFE_FIXME[Parameter Not Nullable]
Matcher match = regex.matcher(contentType);
if (match.find()) {
// NULLSAFE_FIXME[Parameter Not Nullable]
processMultipartResponse(url, r, match.group(1), outputFile, bundleInfo, callback);
} else {
// In case the server doesn't support multipart/mixed responses, fallback to normal
Expand All @@ -152,8 +154,10 @@ public void onResponse(Call call, final Response response) throws IOException {
url,
r.code(),
r.headers(),
// NULLSAFE_FIXME[Nullable Dereference]
r.body().source(),
outputFile,
// NULLSAFE_FIXME[Parameter Not Nullable]
bundleInfo,
callback);
}
Expand All @@ -173,6 +177,7 @@ private void processMultipartResponse(
throws IOException {

MultipartStreamReader bodyReader =
// NULLSAFE_FIXME[Nullable Dereference]
new MultipartStreamReader(response.body().source(), boundary);
boolean completed =
bodyReader.readAllParts(
Expand All @@ -192,6 +197,7 @@ public void onChunkComplete(
status = Integer.parseInt(headers.get("X-Http-Status"));
}
processBundleResult(
// NULLSAFE_FIXME[Parameter Not Nullable]
url, status, Headers.of(headers), body, outputFile, bundleInfo, callback);
} else {
if (!headers.containsKey("Content-Type")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import java.io.Closeable;
Expand All @@ -21,7 +22,8 @@
import okhttp3.WebSocketListener;

/** Java wrapper around a C++ InspectorPackagerConnection. */
/* package */ class CxxInspectorPackagerConnection implements IInspectorPackagerConnection {
/* package */ @Nullsafe(Nullsafe.Mode.LOCAL)
class CxxInspectorPackagerConnection implements IInspectorPackagerConnection {
static {
DevSupportSoLoader.staticInit();
}
Expand All @@ -39,7 +41,7 @@ private static native HybridData initHybrid(

public native void closeQuietly();

public native void sendEventToAllConnections(String event);
public native void sendEventToAllConnections(@Nullable String event);

/** Java wrapper around a C++ IWebSocketDelegate, allowing us to call the interface from Java. */
@DoNotStrip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.ReactConstants;
Expand All @@ -26,7 +27,8 @@
* Helper class for controlling overlay view with FPS and JS FPS info that gets added directly
* to @{link WindowManager} instance.
*/
/* package */ class DebugOverlayController {
/* package */ @Nullsafe(Nullsafe.Mode.LOCAL)
class DebugOverlayController {

public static void requestPermission(Context context) {
// Get permission to show debug overlay in dev builds.
Expand Down Expand Up @@ -57,6 +59,7 @@ private static boolean hasPermission(Context context, String permission) {
PackageInfo info =
context
.getPackageManager()
// NULLSAFE_FIXME[Nullable Dereference]
.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
Expand All @@ -73,7 +76,7 @@ private static boolean hasPermission(Context context, String permission) {

private static boolean canHandleIntent(Context context, Intent intent) {
PackageManager packageManager = context.getPackageManager();
return intent.resolveActivity(packageManager) != null;
return packageManager != null && intent.resolveActivity(packageManager) != null;
}

private final WindowManager mWindowManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
Expand Down Expand Up @@ -59,6 +60,7 @@
* <li>Genymotion emulator with default settings: 10.0.3.2
* </ul>
*/
@Nullsafe(Nullsafe.Mode.LOCAL)
public class DevServerHelper {
private static final int HTTP_CONNECT_TIMEOUT_MS = 5000;

Expand Down Expand Up @@ -205,10 +207,13 @@ public void openInspectorConnection() {
protected Void doInBackground(Void... params) {
Map<String, String> metadata =
AndroidInfoHelpers.getInspectorHostMetadata(mApplicationContext);

String deviceName = metadata.get("deviceName");
if (deviceName == null) {
FLog.w(ReactConstants.TAG, "Could not get device name from Inspector Host Metadata.");
return null;
}
mInspectorPackagerConnection =
new CxxInspectorPackagerConnection(
getInspectorDeviceUrl(), metadata.get("deviceName"), mPackageName);
new CxxInspectorPackagerConnection(getInspectorDeviceUrl(), deviceName, mPackageName);
mInspectorPackagerConnection.connect();
return null;
}
Expand Down Expand Up @@ -447,7 +452,7 @@ public String getSourceUrl(String mainModuleName) {
final Request request = new Request.Builder().url(resourceURL).build();

try (Response response = mClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
if (!response.isSuccessful() || response.body() == null) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.common.JavascriptException;
import com.facebook.react.common.annotations.VisibleForTesting;
import java.io.IOException;
Expand All @@ -29,6 +30,7 @@
import okhttp3.WebSocketListener;

/** A wrapper around WebSocketClient that recognizes RN debugging message format. */
@Nullsafe(Nullsafe.Mode.LOCAL)
class JSDebuggerWebSocketClient extends WebSocketListener {

private static final String TAG = "JSDebuggerWebSocketClient";
Expand Down Expand Up @@ -210,7 +212,7 @@ public void onMessage(@Nullable WebSocket webSocket, String text) {
}

@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
public void onFailure(@Nullable WebSocket webSocket, Throwable t, @Nullable Response response) {
abort("Websocket exception", t);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@

package com.facebook.react.devsupport;

import com.facebook.infer.annotation.Nullsafe;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import okio.Buffer;
import okio.BufferedSource;
import okio.ByteString;

/** Utility class to parse the body of a response of type multipart/mixed. */
@Nullsafe(Nullsafe.Mode.LOCAL)
class MultipartStreamReader {
// Standard line separator for HTTP.
private static final String CRLF = "\r\n";
Expand Down Expand Up @@ -60,7 +63,7 @@ private void emitChunk(Buffer chunk, boolean done, ChunkListener listener) throw
ByteString marker = ByteString.encodeUtf8(CRLF + CRLF);
long indexOfMarker = chunk.indexOf(marker);
if (indexOfMarker == -1) {
listener.onChunkComplete(null, chunk, done);
listener.onChunkComplete(Collections.emptyMap(), chunk, done);
} else {
Buffer headers = new Buffer();
Buffer body = new Buffer();
Expand Down Expand Up @@ -148,6 +151,7 @@ public boolean readAllParts(ChunkListener listener) throws IOException {
Buffer chunk = new Buffer();
content.skip(chunkStart);
content.read(chunk, length);
// NULLSAFE_FIXME[Parameter Not Nullable]
emitProgress(currentHeaders, chunk.size() - currentHeadersLength, true, listener);
emitChunk(chunk, isCloseDelimiter, listener);
currentHeaders = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
package com.facebook.react.devsupport;

import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Assertions;
import com.facebook.infer.annotation.Nullsafe;
import com.facebook.react.bridge.JavaOnlyArray;
import com.facebook.react.bridge.JavaOnlyMap;
import com.facebook.react.bridge.ReadableArray;
Expand All @@ -26,6 +28,7 @@
import org.json.JSONObject;

/** Helper class converting JS and Java stack traces into arrays of {@link StackFrame} objects. */
@Nullsafe(Nullsafe.Mode.LOCAL)
public class StackTraceHelper {

public static final String COLUMN_KEY = "column";
Expand All @@ -49,27 +52,29 @@ public class StackTraceHelper {

/** Represents a generic entry in a stack trace, be it originally from JS or Java. */
public static class StackFrameImpl implements StackFrame {
private final String mFile;
@Nullable private final String mFile;
private final String mMethod;
private final int mLine;
private final int mColumn;
private final String mFileName;
@Nullable private final String mFileName;
private final boolean mIsCollapsed;

private StackFrameImpl(String file, String method, int line, int column, boolean isCollapsed) {
private StackFrameImpl(
@Nullable String file, String method, int line, int column, boolean isCollapsed) {
mFile = file;
mMethod = method;
mLine = line;
mColumn = column;
mFileName = file != null ? new File(file).getName() : "";
mFileName = file != null ? new File(file).getName() : null;
mIsCollapsed = isCollapsed;
}

private StackFrameImpl(String file, String method, int line, int column) {
private StackFrameImpl(@Nullable String file, String method, int line, int column) {
this(file, method, line, column, false);
}

private StackFrameImpl(String file, String fileName, String method, int line, int column) {
private StackFrameImpl(
@Nullable String file, @Nullable String fileName, String method, int line, int column) {
mFile = file;
mFileName = fileName;
mMethod = method;
Expand All @@ -84,7 +89,8 @@ private StackFrameImpl(String file, String fileName, String method, int line, in
* <p>JS traces return the full path to the file here, while Java traces only return the file
* name (the path is not known).
*/
public String getFile() {
@Override
public @Nullable String getFile() {
return mFile;
}

Expand All @@ -109,7 +115,8 @@ public int getColumn() {
* <p>For JS traces this is different from {@link #getFile()} in that it only returns the file
* name, not the full path. For Java traces there is no difference.
*/
public String getFileName() {
@Override
public @Nullable String getFileName() {
return mFileName;
}

Expand All @@ -119,9 +126,10 @@ public boolean isCollapsed() {

/** Convert the stack frame to a JSON representation. */
public JSONObject toJSON() {
String file = getFile();
return new JSONObject(
MapBuilder.of(
"file", getFile(),
"file", (file == null) ? "" : file,
"methodName", getMethod(),
"lineNumber", getLine(),
"column", getColumn(),
Expand All @@ -136,25 +144,33 @@ public JSONObject toJSON() {
public static StackFrame[] convertJsStackTrace(@Nullable ReadableArray stack) {
int size = stack != null ? stack.size() : 0;
StackFrame[] result = new StackFrame[size];
for (int i = 0; i < size; i++) {
ReadableType type = stack.getType(i);
if (type == ReadableType.Map) {
ReadableMap frame = stack.getMap(i);
String methodName = frame.getString("methodName");
String fileName = frame.getString("file");
boolean collapse =
frame.hasKey("collapse") && !frame.isNull("collapse") && frame.getBoolean("collapse");
int lineNumber = -1;
if (frame.hasKey(LINE_NUMBER_KEY) && !frame.isNull(LINE_NUMBER_KEY)) {
lineNumber = frame.getInt(LINE_NUMBER_KEY);
}
int columnNumber = -1;
if (frame.hasKey(COLUMN_KEY) && !frame.isNull(COLUMN_KEY)) {
columnNumber = frame.getInt(COLUMN_KEY);
if (stack != null) {
for (int i = 0; i < size; i++) {
ReadableType type = stack.getType(i);
if (type == ReadableType.Map) {
ReadableMap frame = stack.getMap(i);
Assertions.assertNotNull(frame);
String methodName = frame.getString("methodName");
String fileName = frame.getString("file");
Assertions.assertNotNull(fileName);
Assertions.assertNotNull(methodName);
boolean collapse =
frame.hasKey("collapse") && !frame.isNull("collapse") && frame.getBoolean("collapse");
int lineNumber = -1;
if (frame.hasKey(LINE_NUMBER_KEY) && !frame.isNull(LINE_NUMBER_KEY)) {
lineNumber = frame.getInt(LINE_NUMBER_KEY);
}
int columnNumber = -1;
if (frame.hasKey(COLUMN_KEY) && !frame.isNull(COLUMN_KEY)) {
columnNumber = frame.getInt(COLUMN_KEY);
}
result[i] = new StackFrameImpl(fileName, methodName, lineNumber, columnNumber, collapse);
} else if (type == ReadableType.String) {
String stackFrame = stack.getString(i);
if (stackFrame != null) {
result[i] = new StackFrameImpl(null, stackFrame, -1, -1);
}
}
result[i] = new StackFrameImpl(fileName, methodName, lineNumber, columnNumber, collapse);
} else if (type == ReadableType.String) {
result[i] = new StackFrameImpl(null, stack.getString(i), -1, -1);
}
}
return result;
Expand Down Expand Up @@ -203,15 +219,22 @@ public static StackFrame[] convertJsStackTrace(String stack) {
} else if (matcher1.find()) {
matcher = matcher1;
} else {
result[i] = new StackFrameImpl(null, stackTrace[i], -1, -1);
String unmatchedStackFrame = stackTrace[i];
if (unmatchedStackFrame != null) {
result[i] = new StackFrameImpl(null, unmatchedStackFrame, -1, -1);
}
continue;
}
String fileName = matcher.group(2);
String methodName = matcher.group(1) == null ? "(unknown)" : matcher.group(1);
String lineString = matcher.group(3);
String columnString = matcher.group(4);
if (methodName == null || fileName == null || lineString == null || columnString == null) {
continue;
}
result[i] =
new StackFrameImpl(
matcher.group(2),
matcher.group(1) == null ? "(unknown)" : matcher.group(1),
Integer.parseInt(matcher.group(3)),
Integer.parseInt(matcher.group(4)));
fileName, methodName, Integer.parseInt(lineString), Integer.parseInt(columnString));
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public interface StackFrame {
public val file: String?

/** Get the name of the method this frame points to. */
public val method: String?
public val method: String

/** Get the line number this frame points to in the file returned by [.getFile]. */
public val line: Int
Expand All @@ -40,5 +40,5 @@ public interface StackFrame {
public val isCollapsed: Boolean

/** Convert the stack frame to a JSON representation. */
public fun toJSON(): JSONObject?
public fun toJSON(): JSONObject
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class JSDebuggerWebSocketClientTest {
val client = spy(JSDebuggerWebSocketClient())
val injectedObjects = mapOf("key1" to "value1", "key2" to "value2")
client.loadBundle(
"http://localhost:8080/index.js", injectedObjects as HashMap<String, String>?, cb)
"http://localhost:8080/index.js", injectedObjects as HashMap<String, String>, cb)
verify(client)
.sendMessage(
0,
Expand Down
Loading
Loading