Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
exit 0
fi
echo "Previous tag is $PREV_TAG"
# The HAR embeds librnupdate.so compiled from cpp/patch_core,
# The HAR embeds librnpushy.so compiled from cpp/patch_core,
# cpp/update_flow_core, android/jni/hpatch.c and the HDiffPatch/lzma
# submodules (harmony/pushy/src/main/cpp/CMakeLists.txt), so any of
# those changing must rebuild it too — reusing the previous HAR
Expand All @@ -60,7 +60,7 @@ jobs:
fi

# Rebuild the Android native libraries from source so the published package
# can never ship a stale librnupdate.so after a cpp/patch_core change (the
# can never ship a stale librnpushy.so after a cpp/patch_core change (the
# committed binaries are for local dev / git installs only).
build_android_so:
runs-on: ubuntu-latest # npm --provenance requires a GitHub-hosted runner
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ add_library(rnoh_app SHARED
"${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_include_directories(rnoh_app PRIVATE "${PUSHY_CPP_DIR}")
# Pushy's RNOH glue is compiled into rnoh_app directly. librnupdate.so comes from pushy.har.
# Pushy's RNOH glue is compiled into rnoh_app directly. librnpushy.so comes from pushy.har.
target_sources(rnoh_app PRIVATE "${PUSHY_CPP_DIR}/PushyTurboModule.cpp")
target_link_libraries(rnoh_app PUBLIC rnoh)
3 changes: 2 additions & 1 deletion android/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := rnupdate
LOCAL_MODULE := rnpushy
LOCAL_CPPFLAGS += -std=c++17
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
LOCAL_C_INCLUDES := \
Expand All @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := \
../../cpp/patch_core/digest.cpp \
../../cpp/patch_core/hbc_transform.cpp \
../../cpp/patch_core/hbc_transform_wire.cpp \
../../cpp/patch_core/jni_registration.cpp \
../../cpp/patch_core/patch_core.cpp \
../../cpp/patch_core/patch_core_android.cpp \
../../cpp/patch_core/state_core.cpp \
Expand Down
Binary file added android/lib/arm64-v8a/librnpushy.so
Binary file not shown.
Binary file removed android/lib/arm64-v8a/librnupdate.so
Binary file not shown.
Binary file added android/lib/armeabi-v7a/librnpushy.so
Binary file not shown.
Binary file removed android/lib/armeabi-v7a/librnupdate.so
Binary file not shown.
Binary file added android/lib/x86/librnpushy.so
Binary file not shown.
Binary file removed android/lib/x86/librnupdate.so
Binary file not shown.
Binary file added android/lib/x86_64/librnpushy.so
Binary file not shown.
Binary file removed android/lib/x86_64/librnupdate.so
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
final class ApkInstaller {
private static final int COPY_BUFFER_SIZE = 64 * 1024;
private static final String SESSION_ID_EXTRA =
"cn.reactnative.modules.update.extra.PACKAGE_INSTALLER_SESSION_ID";
Texts.reveal("3919bac3ab8a6b512c3e08f0c0b6de60452311edfbc8f680624b2d1de38da5a58e65557f3ecaeb8ea3b859661f3dc3f98bab48646c042bd0e19ca546681c2939");
private static final ConcurrentHashMap<Integer, Promise> pendingPromises =
new ConcurrentHashMap<Integer, Promise>();

Expand Down Expand Up @@ -116,7 +116,7 @@ private static boolean declaresInstallPermission(
} catch (Throwable error) {
// A package manager that cannot answer is treated as "not declared":
// the caller rejects with a code the app can act on.
Log.e(UpdateContext.TAG, "Unable to inspect requested permissions", error);
Log.e(Texts.LOG_TAG, "Unable to inspect requested permissions", error);
}
return false;
}
Expand Down Expand Up @@ -205,7 +205,7 @@ static void install(
// The session is already in the system's hands (only session
// close failed): the status receiver owns the promise now, so
// settling here would be a second, contradictory outcome.
Log.w(UpdateContext.TAG, "Install session reported an error after commit", error);
Log.w(Texts.LOG_TAG, "Install session reported an error after commit", error);
return;
}
if (sessionId != -1) {
Expand All @@ -214,14 +214,14 @@ static void install(
try {
packageInstaller.abandonSession(sessionId);
} catch (Throwable abandonError) {
Log.w(UpdateContext.TAG, "Unable to abandon failed install session", abandonError);
Log.w(Texts.LOG_TAG, "Unable to abandon failed install session", abandonError);
}
}
}
promise.reject(ErrorCodes.APK_INSTALL_FAILED, "Unable to stage APK installation", error);
} finally {
if (apkFile.exists() && !apkFile.delete()) {
Log.w(UpdateContext.TAG, "Unable to delete staged APK " + apkFile);
Log.w(Texts.LOG_TAG, "Unable to delete staged APK " + apkFile);
}
}
}
Expand Down Expand Up @@ -281,7 +281,7 @@ private static void rejectPending(int sessionId, String message, Throwable error
promise.reject(ErrorCodes.APK_INSTALL_FAILED, message, error);
}
} else {
Log.e(UpdateContext.TAG, message, error);
Log.e(Texts.LOG_TAG, message, error);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ void copyFromResource(
// failure, not a skip: record it and fail the update
// after the loop so a broken update is not activated.
Log.e(
UpdateContext.TAG,
Texts.LOG_TAG,
"Failed to copy resource "
+ actualSourcePath
+ " to "
Expand Down Expand Up @@ -230,7 +230,7 @@ void copyFromResource(

if (!remainingFiles.isEmpty()) {
Log.w(
UpdateContext.TAG,
Texts.LOG_TAG,
"Skipped " + remainingFiles.size() + " missing bundled resources"
);
}
Expand Down Expand Up @@ -368,7 +368,7 @@ private ArrayList<String> collectApkPaths() {
}
} catch (PackageManager.NameNotFoundException e) {
if (UpdateContext.DEBUG) {
Log.w(UpdateContext.TAG, "Failed to get application info: " + e.getMessage());
Log.w(Texts.LOG_TAG, "Failed to get application info: " + e.getMessage());
}
}

Expand All @@ -381,7 +381,7 @@ private void closeZipFiles(HashMap<String, SafeZipFile> zipFileMap) {
zipFile.close();
} catch (IOException e) {
if (UpdateContext.DEBUG) {
Log.w(UpdateContext.TAG, "Failed to close zip file", e);
Log.w(Texts.LOG_TAG, "Failed to close zip file", e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
* waits with a hard timeout, so even a deadlocked rescue (a thread that died
* holding a lock) can only delay the process death, never prevent it.
*/
final class CrashRescue {
final class CrashHold {
private static final AtomicBoolean installed = new AtomicBoolean(false);
private static final AtomicBoolean rescueAttempted = new AtomicBoolean(false);
private static final AtomicBoolean holdAttempted = new AtomicBoolean(false);
// ≈ process start: install() runs during the first bundle resolution.
// Deliberately not Process.getStartElapsedRealtime(), which is API 24+
// while the module's minSdk floor is lower — a NoSuchMethodError here
Expand All @@ -33,7 +33,7 @@ final class CrashRescue {
// A held main thread stops input dispatch; stay under the ~5s ANR window.
private static final long BUDGET_MAIN_THREAD_MILLIS = 3500;

private CrashRescue() {
private CrashHold() {
}

static void install() {
Expand All @@ -47,7 +47,7 @@ static void install() {
@Override
public void uncaughtException(Thread thread, Throwable error) {
try {
maybeHoldForRescue(thread);
maybeHold(thread);
} catch (Throwable ignored) {
// The dying process owes the previous handler its turn no
// matter what the rescue did.
Expand All @@ -64,16 +64,16 @@ public void uncaughtException(Thread thread, Throwable error) {
});
}

private static void maybeHoldForRescue(Thread crashedThread) {
private static void maybeHold(Thread crashedThread) {
// Once per process; a second crashing thread passes straight through
// instead of waiting behind the first (§11.3: prefer under-rescuing
// over wedging the teardown).
if (!rescueAttempted.compareAndSet(false, true)) {
if (!holdAttempted.compareAndSet(false, true)) {
return;
}
long uptimeMillis =
SystemClock.elapsedRealtime() - installedAtElapsedRealtime;
boolean roundInFlight = NativeCheckOrchestrator.isRoundInFlight();
boolean roundInFlight = SyncCoordinator.isRoundInFlight();
// Early crashes are the brick signature; a crash with an in-flight
// round is worth finishing regardless of uptime. Everything else is
// an ordinary crash whose UX must not be delayed.
Expand All @@ -86,27 +86,27 @@ private static void maybeHoldForRescue(Thread crashedThread) {
: BUDGET_BACKGROUND_THREAD_MILLIS;
final long deadlineNanos =
System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(budgetMillis);
Log.i(UpdateContext.TAG, "crash rescue: holding process for up to "
Log.i(Texts.LOG_TAG, "crash hold: holding process for up to "
+ budgetMillis + "ms (uptime " + uptimeMillis + "ms)");

final CountDownLatch done = new CountDownLatch(1);
Thread worker = new Thread(new Runnable() {
@Override
public void run() {
try {
NativeCheckOrchestrator.runRescue(deadlineNanos);
SyncCoordinator.runHoldRound(deadlineNanos);
} catch (Throwable e) {
Log.w(UpdateContext.TAG, "crash rescue failed: " + e);
Log.w(Texts.LOG_TAG, "crash hold failed: " + e);
} finally {
done.countDown();
}
}
}, "pushy-crash-rescue");
}, "pushy-crash-hold");
worker.setDaemon(true);
worker.start();
try {
if (!done.await(budgetMillis, TimeUnit.MILLISECONDS)) {
Log.w(UpdateContext.TAG, "crash rescue: budget exhausted, letting go");
Log.w(Texts.LOG_TAG, "crash hold: budget exhausted, letting go");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Expand Down
Loading
Loading