react-native-update 10.59.1 → 10.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/README-CN.md +7 -7
  2. package/README.md +7 -6
  3. package/android/build.gradle +25 -33
  4. package/android/jni/Android.mk +16 -24
  5. package/android/lib/arm64-v8a/librnpushy.so +0 -0
  6. package/android/lib/armeabi-v7a/librnpushy.so +0 -0
  7. package/android/lib/x86/librnpushy.so +0 -0
  8. package/android/lib/x86_64/librnpushy.so +0 -0
  9. package/android/proguard.pro +9 -7
  10. package/android/src/main/java/cn/reactnative/modules/update/ApkInstaller.java +11 -12
  11. package/android/src/main/java/cn/reactnative/modules/update/ArchiveLimits.java +23 -6
  12. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +50 -51
  13. package/android/src/main/java/cn/reactnative/modules/update/CleanupKeepNames.java +12 -13
  14. package/android/src/main/java/cn/reactnative/modules/update/CopyGroupResult.java +3 -0
  15. package/android/src/main/java/cn/reactnative/modules/update/CrashHold.java +22 -30
  16. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +181 -332
  17. package/android/src/main/java/cn/reactnative/modules/update/DownloadTaskParams.java +3 -1
  18. package/android/src/main/java/cn/reactnative/modules/update/ErrorCodes.java +27 -0
  19. package/android/src/main/java/cn/reactnative/modules/update/FileOperationException.java +1 -1
  20. package/android/src/main/java/cn/reactnative/modules/update/FlowBridge.java +32 -8
  21. package/android/src/main/java/cn/reactnative/modules/update/HttpClients.java +63 -0
  22. package/android/src/main/java/cn/reactnative/modules/update/HttpUtils.java +0 -11
  23. package/android/src/main/java/cn/reactnative/modules/update/InstallRecord.java +66 -116
  24. package/android/src/main/java/cn/reactnative/modules/update/NativeCore.java +9 -1
  25. package/android/src/main/java/cn/reactnative/modules/update/PatchFailedException.java +1 -1
  26. package/android/src/main/java/cn/reactnative/modules/update/PushyRuntime.java +32 -60
  27. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +8 -23
  28. package/android/src/main/java/cn/reactnative/modules/update/SafeZipFile.java +42 -80
  29. package/android/src/main/java/cn/reactnative/modules/update/StateSerialRunner.java +22 -39
  30. package/android/src/main/java/cn/reactnative/modules/update/SyncCoordinator.java +176 -299
  31. package/android/src/main/java/cn/reactnative/modules/update/Threads.java +35 -0
  32. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +242 -174
  33. package/android/src/main/java/cn/reactnative/modules/update/UpdateEventEmitter.java +1 -1
  34. package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +75 -17
  35. package/android/src/main/java/cn/reactnative/modules/update/{UpdateModuleImpl.java → UpdateModule.java} +113 -95
  36. package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +16 -19
  37. package/android/src/oldarch/cn/reactnative/modules/update/NativePushySpec.java +69 -0
  38. package/cpp/android_jni/archive_limits_jni.cpp +83 -0
  39. package/cpp/android_jni/install_record_jni.cpp +89 -0
  40. package/cpp/android_jni/jni_log.h +31 -0
  41. package/cpp/android_jni/jni_natives.h +40 -0
  42. package/cpp/android_jni/jni_registration.cpp +133 -0
  43. package/cpp/android_jni/jni_util.h +160 -0
  44. package/cpp/android_jni/update_core_android.cpp +450 -0
  45. package/cpp/android_jni/update_flow_jni.cpp +133 -0
  46. package/{android/jni → cpp/hpatch}/hpatch.c +5 -5
  47. package/{android/jni → cpp/hpatch}/hpatch.h +4 -1
  48. package/cpp/patch_core/archive_limits.cpp +194 -0
  49. package/cpp/patch_core/archive_limits.h +99 -10
  50. package/cpp/patch_core/archive_patch_core.cpp +96 -12
  51. package/cpp/patch_core/archive_patch_core.h +49 -0
  52. package/cpp/patch_core/digest.h +5 -4
  53. package/cpp/patch_core/error_codes.h +5 -3
  54. package/cpp/patch_core/install_record.cpp +430 -0
  55. package/cpp/patch_core/install_record.h +163 -9
  56. package/cpp/patch_core/patch_core.cpp +62 -16
  57. package/cpp/patch_core/patch_core.h +27 -7
  58. package/cpp/patch_core/patch_manifest.cpp +201 -0
  59. package/cpp/patch_core/patch_manifest.h +74 -0
  60. package/cpp/patch_core/state_ops.h +3 -3
  61. package/cpp/update_flow_core/flow_json.cpp +82 -8
  62. package/cpp/update_flow_core/flow_json.h +21 -0
  63. package/cpp/update_flow_core/native_config.cpp +456 -0
  64. package/cpp/update_flow_core/native_config.h +84 -0
  65. package/cpp/update_flow_core/native_round.cpp +326 -0
  66. package/cpp/update_flow_core/native_round.h +90 -0
  67. package/cpp/update_flow_core/update_flow_core.h +2 -2
  68. package/harmony/hvigor-plugin.ts +11 -19
  69. package/harmony/pushy/src/main/cpp/CMakeLists.txt +19 -26
  70. package/harmony/pushy/src/main/cpp/PushyPackage.h +2 -2
  71. package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +55 -94
  72. package/harmony/pushy/src/main/cpp/pushy.cpp +694 -517
  73. package/harmony/pushy/src/main/ets/ArchiveLimits.ts +48 -72
  74. package/harmony/pushy/src/main/ets/DownloadTask.ts +164 -404
  75. package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +1 -3
  76. package/harmony/pushy/src/main/ets/ErrorCodes.ts +1 -14
  77. package/harmony/pushy/src/main/ets/EventHub.ts +1 -1
  78. package/harmony/pushy/src/main/ets/InstallRecord.ts +52 -151
  79. package/harmony/pushy/src/main/ets/Logger.ts +20 -34
  80. package/harmony/pushy/src/main/ets/NativePatchCore.ts +116 -42
  81. package/harmony/pushy/src/main/ets/PushyConfiguration.ts +8 -85
  82. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +11 -25
  83. package/harmony/pushy/src/main/ets/SaveFile.ts +99 -18
  84. package/harmony/pushy/src/main/ets/SyncCoordinator.ts +136 -335
  85. package/harmony/pushy/src/main/ets/Texts.ts +0 -4
  86. package/harmony/pushy/src/main/ets/UpdateContext.ts +106 -119
  87. package/harmony/pushy.har +0 -0
  88. package/ios/RCTPushy/RCTPushy+Launch.mm +185 -0
  89. package/ios/RCTPushy/RCTPushy.h +12 -0
  90. package/ios/RCTPushy/RCTPushy.mm +87 -2628
  91. package/ios/RCTPushy/RCTPushyCommon.h +34 -0
  92. package/ios/RCTPushy/RCTPushyConfiguration.h +0 -8
  93. package/ios/RCTPushy/RCTPushyConfiguration.mm +40 -121
  94. package/ios/RCTPushy/RCTPushyDownloader.mm +40 -37
  95. package/ios/RCTPushy/RCTPushyInstallRecord.mm +61 -0
  96. package/ios/RCTPushy/RCTPushyInstaller.mm +689 -0
  97. package/ios/RCTPushy/RCTPushyInternal.h +144 -0
  98. package/ios/RCTPushy/RCTPushyOrchestrator.mm +1001 -0
  99. package/ios/RCTPushy/RCTPushyState.mm +314 -0
  100. package/package.json +25 -23
  101. package/react-native-update.podspec +74 -83
  102. package/src/client.ts +361 -451
  103. package/src/context.ts +1 -1
  104. package/src/core.ts +35 -8
  105. package/src/endpoint.ts +0 -2
  106. package/src/error.ts +13 -32
  107. package/src/i18n.ts +18 -83
  108. package/src/locales/en.ts +0 -4
  109. package/src/locales/zh.ts +0 -4
  110. package/src/provider.tsx +60 -53
  111. package/src/telemetry.ts +0 -13
  112. package/src/type.ts +0 -15
  113. package/src/updateFlowCore.ts +116 -10
  114. package/src/utils.ts +49 -42
  115. package/android/src/main/java/cn/reactnative/modules/update/ArchivePatchPlanResult.java +0 -6
  116. package/android/src/main/java/cn/reactnative/modules/update/PushyConfiguration.java +0 -104
  117. package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +0 -37
  118. package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +0 -121
  119. package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +0 -125
  120. package/cpp/patch_core/jni_natives.h +0 -27
  121. package/cpp/patch_core/jni_registration.cpp +0 -103
  122. package/cpp/patch_core/jni_util.h +0 -60
  123. package/cpp/patch_core/patch_core_android.cpp +0 -97
  124. package/cpp/patch_core/update_core_android.cpp +0 -485
  125. package/cpp/update_flow_core/update_flow_jni.cpp +0 -150
@@ -0,0 +1,83 @@
1
+ // JNI glue of ArchiveLimits.java over the shared extraction accounting
2
+ // (cpp/patch_core/archive_limits.h).
3
+ #include <jni.h>
4
+
5
+ #include <string>
6
+ #include <vector>
7
+
8
+ #include "jni_natives.h"
9
+ #include "jni_util.h"
10
+ #include "../patch_core/archive_limits.h"
11
+
12
+ namespace {
13
+
14
+ using pushy::jni_util::GuardJni;
15
+ using pushy::jni_util::JArrayToVector;
16
+ using pushy::jni_util::ThrowRuntimeException;
17
+
18
+ void ThrowIOException(JNIEnv* env, const std::string& message) {
19
+ jclass exception = env->FindClass("java/io/IOException");
20
+ if (exception != nullptr) {
21
+ env->ThrowNew(exception, message.c_str());
22
+ }
23
+ }
24
+
25
+ } // namespace
26
+
27
+ // One call per archive: the central directory's names and declared sizes
28
+ // through an EntryAccumulator. Returns the total uncompressed size, or throws
29
+ // an IOException with the first violation.
30
+ jlong pushy::jni_natives::ArchiveCheckEntries(
31
+ JNIEnv* env, jclass, jlong archive_bytes, jobjectArray names,
32
+ jlongArray sizes, jlongArray compressed_sizes) {
33
+ return GuardJni(
34
+ env, "Unexpected native exception while checking an archive", [&]() -> jlong {
35
+ const jsize count = names == nullptr ? 0 : env->GetArrayLength(names);
36
+ if (sizes == nullptr || compressed_sizes == nullptr ||
37
+ env->GetArrayLength(sizes) != count ||
38
+ env->GetArrayLength(compressed_sizes) != count) {
39
+ ThrowRuntimeException(env, "archive entry arrays differ in length");
40
+ return 0;
41
+ }
42
+ // Before any name is copied: a hostile central directory may list far
43
+ // more entries than the cap.
44
+ pushy::delta::Status status = pushy::archive_limits::CheckEntryCount(count);
45
+ if (!status.ok) {
46
+ ThrowIOException(env, status.message);
47
+ return 0;
48
+ }
49
+ const std::vector<std::string> entry_names = JArrayToVector(env, names);
50
+ std::vector<jlong> size_values(static_cast<size_t>(count));
51
+ std::vector<jlong> compressed_values(static_cast<size_t>(count));
52
+ if (count > 0) {
53
+ env->GetLongArrayRegion(sizes, 0, count, size_values.data());
54
+ env->GetLongArrayRegion(compressed_sizes, 0, count, compressed_values.data());
55
+ }
56
+ pushy::archive_limits::EntryAccumulator accumulator(archive_bytes);
57
+ for (jsize i = 0; i < count; i++) {
58
+ status = accumulator.Accept(size_values[i], compressed_values[i], false,
59
+ entry_names[i]);
60
+ if (!status.ok) {
61
+ ThrowIOException(env, status.message);
62
+ return 0;
63
+ }
64
+ }
65
+ return accumulator.total_uncompressed();
66
+ });
67
+ }
68
+
69
+ // {bytes to probe for (0: no probe), reservation end} before one chunk of a
70
+ // download is written.
71
+ jlongArray pushy::jni_natives::ArchivePlanFreeSpaceProbe(
72
+ JNIEnv* env, jclass, jlong known_total, jlong written_before,
73
+ jlong chunk_bytes, jlong reserved_until) {
74
+ const pushy::archive_limits::FreeSpaceProbe plan =
75
+ pushy::archive_limits::PlanUnknownLengthFreeSpaceProbe(
76
+ known_total, written_before, chunk_bytes, reserved_until);
77
+ jlongArray result = env->NewLongArray(2);
78
+ if (result != nullptr) {
79
+ const jlong values[2] = {plan.probe ? plan.reserve : 0, plan.reserved_until};
80
+ env->SetLongArrayRegion(result, 0, 2, values);
81
+ }
82
+ return result;
83
+ }
@@ -0,0 +1,89 @@
1
+ // JNI glue of InstallRecord.java over the shared completion record core
2
+ // (cpp/patch_core/install_record.h). The jstring-returning natives return
3
+ // null on success and the reason otherwise; Java turns a reason into an
4
+ // IOException.
5
+ #include <jni.h>
6
+
7
+ #include <string>
8
+
9
+ #include "jni_natives.h"
10
+ #include "jni_util.h"
11
+ #include "../patch_core/install_record.h"
12
+
13
+ namespace {
14
+
15
+ using pushy::jni_util::GuardJni;
16
+ using pushy::jni_util::JStringToString;
17
+ using pushy::jni_util::ToJString;
18
+
19
+ jstring ReasonOrNull(JNIEnv* env, const pushy::delta::Status& status) {
20
+ return status.ok ? nullptr : ToJString(env, status.message);
21
+ }
22
+
23
+ } // namespace
24
+
25
+ jboolean pushy::jni_natives::InstallRecordIsComplete(
26
+ JNIEnv* env, jclass, jstring version_dir, jstring version_hash,
27
+ jstring bundle_file_name) {
28
+ return GuardJni(
29
+ env, "Unexpected native exception while reading a completion record", [&] {
30
+ return pushy::install_record::IsComplete(
31
+ JStringToString(env, version_dir),
32
+ JStringToString(env, version_hash),
33
+ JStringToString(env, bundle_file_name))
34
+ ? JNI_TRUE
35
+ : JNI_FALSE;
36
+ });
37
+ }
38
+
39
+ // Hashes the whole bundle: called from worker threads only.
40
+ jstring pushy::jni_natives::InstallRecordCheckActivation(
41
+ JNIEnv* env, jclass, jstring version_dir, jstring version_hash,
42
+ jstring bundle_file_name, jboolean grandfathered) {
43
+ return GuardJni(
44
+ env, "Unexpected native exception while verifying a version", [&] {
45
+ pushy::install_record::Activation activation;
46
+ return ReasonOrNull(
47
+ env, pushy::install_record::CheckActivation(
48
+ JStringToString(env, version_dir),
49
+ JStringToString(env, version_hash),
50
+ JStringToString(env, bundle_file_name),
51
+ grandfathered == JNI_TRUE, &activation));
52
+ });
53
+ }
54
+
55
+ jstring pushy::jni_natives::InstallRecordSeal(
56
+ JNIEnv* env, jclass, jstring staging_dir, jstring version_hash,
57
+ jstring bundle_file_name, jstring artifact_sha256,
58
+ jstring known_bundle_sha256) {
59
+ return GuardJni(
60
+ env, "Unexpected native exception while writing a completion record", [&] {
61
+ return ReasonOrNull(
62
+ env, pushy::install_record::Seal(
63
+ JStringToString(env, staging_dir),
64
+ JStringToString(env, version_hash),
65
+ JStringToString(env, bundle_file_name),
66
+ JStringToString(env, artifact_sha256),
67
+ JStringToString(env, known_bundle_sha256))
68
+ .status);
69
+ });
70
+ }
71
+
72
+ jstring pushy::jni_natives::InstallRecordPromote(
73
+ JNIEnv* env, jclass, jstring staging_dir, jstring version_dir) {
74
+ return GuardJni(
75
+ env, "Unexpected native exception while moving a staged version", [&] {
76
+ return ReasonOrNull(
77
+ env, pushy::install_record::Promote(JStringToString(env, staging_dir),
78
+ JStringToString(env, version_dir)));
79
+ });
80
+ }
81
+
82
+ jstring pushy::jni_natives::InstallRecordBundleSha256(
83
+ JNIEnv* env, jclass, jstring version_dir) {
84
+ return GuardJni(
85
+ env, "Unexpected native exception while reading a completion record", [&] {
86
+ return ToJString(env, pushy::install_record::RecordedBundleSha256(
87
+ JStringToString(env, version_dir)));
88
+ });
89
+ }
@@ -0,0 +1,31 @@
1
+ #ifndef PUSHY_ANDROID_JNI_LOG_H_
2
+ #define PUSHY_ANDROID_JNI_LOG_H_
3
+
4
+ #include <android/log.h>
5
+
6
+ #include "../patch_core/obscured_text.h"
7
+
8
+ // Keep the core internal to whichever binary links it (see podspec Core).
9
+ #pragma GCC visibility push(hidden)
10
+
11
+ namespace pushy {
12
+ namespace jni_log {
13
+
14
+ // Same logcat tag as the Java layer (Texts.LOG_TAG), stored encoded.
15
+ inline const char* Tag() {
16
+ static const char* const tag =
17
+ text::RevealStatic("2812f5d2bac6664436360afc9ba680694b3301");
18
+ return tag;
19
+ }
20
+
21
+ } // namespace jni_log
22
+ } // namespace pushy
23
+
24
+ #pragma GCC visibility pop
25
+
26
+ // Error-level logcat line under the SDK's tag. For JNI binding failures that
27
+ // would otherwise be swallowed: they must be visible in release builds.
28
+ #define PUSHY_JNI_LOGE(...) \
29
+ __android_log_print(ANDROID_LOG_ERROR, ::pushy::jni_log::Tag(), __VA_ARGS__)
30
+
31
+ #endif // PUSHY_ANDROID_JNI_LOG_H_
@@ -0,0 +1,40 @@
1
+ #ifndef PUSHY_ANDROID_JNI_NATIVES_H_
2
+ #define PUSHY_ANDROID_JNI_NATIVES_H_
3
+
4
+ #include <jni.h>
5
+
6
+ // Android native methods. They are registered by name from JNI_OnLoad
7
+ // (jni_registration.cpp) instead of being exported as Java_* symbols, so the
8
+ // shared library's dynamic symbol table carries no class or method names.
9
+ namespace pushy {
10
+ namespace jni_natives {
11
+
12
+ // Called once from JNI_OnLoad: caches the JNI result classes (global refs),
13
+ // their constructors and field IDs. Returns false (after logging what is
14
+ // missing) when any lookup failed; the natives that need the missing class
15
+ // then throw a RuntimeException instead of defaulting fields.
16
+ bool InitResultClassCache(JNIEnv* env);
17
+
18
+ jint SupportedDiffVersion(JNIEnv*, jclass);
19
+ jobject SyncStateWithBinaryVersion(JNIEnv* env, jclass, jstring package_version, jstring build_time, jobject state_result);
20
+ jobject RunStateCore(JNIEnv* env, jclass, jint operation, jobject state_result, jstring string_arg, jboolean flag_a, jboolean flag_b);
21
+ jobjectArray ApplyArchiveDelta(JNIEnv* env, jclass, jint patch_type, jobjectArray entry_names, jbyteArray manifest_json, jstring source_root, jstring target_root, jstring origin_bundle_path, jstring bundle_patch_path, jstring bundle_output_path, jboolean host_copies_resources);
22
+ void CleanupOldEntries(JNIEnv* env, jclass, jstring root_dir, jobjectArray keep_names, jint max_age_days, jstring trash_dir);
23
+ jstring FlowPrepareRound(JNIEnv* env, jclass, jstring configJson, jstring envJson, jdouble randomSample);
24
+ jstring FlowNextQueryStep(JNIEnv* env, jclass, jstring stateJson, jstring responseText);
25
+ jstring FlowHandleResponse(JNIEnv* env, jclass, jstring responseText, jstring configJson, jstring envJson, jstring requestBody, jlong responseAtSeconds);
26
+ jboolean FlowConfigsEquivalent(JNIEnv* env, jclass, jstring a, jstring b);
27
+ jstring FlowRunnableConfig(JNIEnv* env, jclass, jstring configJson);
28
+ jstring FlowNormalizeConfiguration(JNIEnv* env, jclass, jstring optionsJson);
29
+ jboolean InstallRecordIsComplete(JNIEnv* env, jclass, jstring version_dir, jstring version_hash, jstring bundle_file_name);
30
+ jstring InstallRecordCheckActivation(JNIEnv* env, jclass, jstring version_dir, jstring version_hash, jstring bundle_file_name, jboolean grandfathered);
31
+ jstring InstallRecordSeal(JNIEnv* env, jclass, jstring staging_dir, jstring version_hash, jstring bundle_file_name, jstring artifact_sha256, jstring known_bundle_sha256);
32
+ jstring InstallRecordPromote(JNIEnv* env, jclass, jstring staging_dir, jstring version_dir);
33
+ jstring InstallRecordBundleSha256(JNIEnv* env, jclass, jstring version_dir);
34
+ jlong ArchiveCheckEntries(JNIEnv* env, jclass, jlong archive_bytes, jobjectArray names, jlongArray sizes, jlongArray compressed_sizes);
35
+ jlongArray ArchivePlanFreeSpaceProbe(JNIEnv* env, jclass, jlong known_total, jlong written_before, jlong chunk_bytes, jlong reserved_until);
36
+
37
+ } // namespace jni_natives
38
+ } // namespace pushy
39
+
40
+ #endif // PUSHY_ANDROID_JNI_NATIVES_H_
@@ -0,0 +1,133 @@
1
+ // Registers the Android native methods from JNI_OnLoad instead of exporting
2
+ // Java_<package>_<class>_<method> symbols: the shared library then exports only
3
+ // JNI_OnLoad, and the class names, method names and signatures used for
4
+ // registration are stored encoded (obscured_text.h,
5
+ // scripts/encode-native-text.ts). Regenerate the table when a native method
6
+ // is added or its Java signature changes.
7
+ #include <jni.h>
8
+
9
+ #include <string>
10
+ #include <vector>
11
+
12
+ #include "jni_log.h"
13
+ #include "jni_natives.h"
14
+ #include "../patch_core/obscured_text.h"
15
+
16
+ namespace {
17
+
18
+ struct NativeMethod {
19
+ const char* name;
20
+ const char* signature;
21
+ void* function;
22
+ };
23
+
24
+ struct NativeClass {
25
+ const char* name;
26
+ std::vector<NativeMethod> methods;
27
+ };
28
+
29
+ const std::vector<NativeClass>& NativeClasses() {
30
+ static const std::vector<NativeClass> classes = {
31
+ {"3919bbc3ab8a6b512c3e08f0c0b6df60452311edfbc8f780624b2d1de38c8ebc8e7e42342de4daa0", // NativeCore
32
+ {
33
+ {"3d12e0e2bb9b784a302b19fdf2ba966b7c2216f2f7d4b6", "725edd",
34
+ reinterpret_cast<void*>(&pushy::jni_natives::SupportedDiffVersion)},
35
+ }},
36
+ {"3919bbc3ab8a6b512c3e08f0c0b6df60452311edfbc8f780624b2d1de38c95ad9e7640342de4c6b1878768", // UpdateContext
37
+ {
38
+ {"290efad29d9f6951270815edde9199634b351dd7fbc9ab9c7d41", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655c7cbabcd8d79583507feccbe8e7244113617f1c7a3897a09361019fbc3b1de5d5f2911e7dcd3ab9341553e1febd0faf7b77b5b7d1de9c8a5976e7c4e3e02f481a687615753390ab9c6a0896b53214e2defd9a1974c433b03d1c5ceaf9b600a",
39
+ reinterpret_cast<void*>(&pushy::jni_natives::SyncStateWithBinaryVersion)},
40
+ {"2802fae2ba8a7c4001300efc", "723ed8d2a0c47a40233c08f7d7a7997b4f6809eefaceb49061003919e2c2b4b8d54440301aeeebaa909a4e5c2506fcd9f1ab6e40483a57f9d3a18b2675371214f4d0efab54020406ecb0cebc977044230bf3cdb7bbd4755a361ae0ccb5cc756d5e3600f481989c64565a1f16e4d682887952281545",
41
+ reinterpret_cast<void*>(&pushy::jni_natives::RunStateCore)},
42
+ }},
43
+ {"3919bbc3ab8a6b512c3e08f0c0b6df60452311edfbc8f780624b2d1de38c84b28d79583e0feffca49194", // DownloadTask
44
+ {
45
+ {"3b07e4ddb7aa7a462a360afcf2b69c794b", "723ecffda48a7e446d331df7d1fca379582e0ae6a5e09ab9784e3a08a9cfa1b39d3867251ce2c6a2d9b376582012bfc1ab89630e6d2f0afcdca8d7454c22161cb5dbb59f69041b11f0f6d2becd5f5a2c1ce68badbf957f1a011bfec0a8843b51503602f081a7896b45100f0de4dabe8a317d6d3a32f8d6fa806a4d2a12edc1c9b381711e2304ecd0aeba8f36432314ecdea2cb42714b2132e0c0b9995446332816e38f",
46
+ reinterpret_cast<void*>(&pushy::jni_natives::ApplyArchiveDelta)},
47
+ {"391bf1d0a09e786a2e3b39f7c2a1996859", "723bfed0b88a274923311bb6e5a7826444205fdad2d1b98373002008e8c4ef8e8e655d3f09b0e189889e6a58791ff1c3adc857554c3216f289e6ba",
48
+ reinterpret_cast<void*>(&pushy::jni_natives::CleanupOldEntries)},
49
+ }},
50
+ {"3919bbc3ab8a6b512c3e08f0c0b6df60452311edfbc8f780624b2d1de38c86b19560762307efcfa0", // FlowBridge
51
+ {
52
+ {"2a05f1c1af996d772d2a12fd", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655cf8189889e6a58791ff1c3adc857554c3216f289",
53
+ reinterpret_cast<void*>(&pushy::jni_natives::FlowPrepareRound)},
54
+ {"3412ecc59f9e6d573b0c08fcc6", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655a2e4af83897d163a12fecae5b4705357351fae",
55
+ reinterpret_cast<void*>(&pushy::jni_natives::FlowNextQueryStep)},
56
+ {"3216fad5a28e5a40312f13f7c5b6", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655c7c2a4949e3355371df78299937648503c43d9d8ae9a68092f0113fd9887857c422602b9d595959c72462c45ebc5afb9d44b412006e2cefd",
57
+ reinterpret_cast<void*>(&pushy::jni_natives::FlowHandleResponse)},
58
+ {"3918fad7a78c7b60332a15efd7bf95635e", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655a2f2",
59
+ reinterpret_cast<void*>(&pushy::jni_natives::FlowConfigsEquivalent)},
60
+ {"2802fadfaf896440013012ffdfb4", "723bfed0b88a274923311bb6e5a7826444205fa8d2d1b98373002008e8c4ef8e8e655d3f09b0",
61
+ reinterpret_cast<void*>(&pushy::jni_natives::FlowRunnableConfig)},
62
+ {"3418e6dcaf87615f271c13f7d0ba9778582610e8f1d5", "723bfed0b88a274923311bb6e5a7826444205fa8d2d1b98373002008e8c4ef8e8e655d3f09b0",
63
+ reinterpret_cast<void*>(&pushy::jni_natives::FlowNormalizeConfiguration)},
64
+ }},
65
+ {"3919bbc3ab8a6b512c3e08f0c0b6df60452311edfbc8f780624b2d1de38c89b38963553d02d9cda68d8d78", // InstallRecord
66
+ {
67
+ {"3304d7dea39b6440363a", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655c7c2a4949e3355371df78299937648503c43bce8",
68
+ reinterpret_cast<void*>(&pushy::jni_natives::InstallRecordIsComplete)},
69
+ {"391ff1d2a5aa6b512b291deddfbc9e", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655c7c2a4949e3355371df78299937648503c43cf9b83866850224f11fbd9b3de5d5f3a0cecf887",
70
+ reinterpret_cast<void*>(&pushy::jni_natives::InstallRecordCheckActivation)},
71
+ {"2912f5dd9d9f69422b311b", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655c7c2a4949e3355371df78299937648503c43d9d8ae9a68092f0113fd9887857c422602b9d3d6b880721f210be9c3ee8d8f6a5c3c08b7808a89616b5b7818f0c0acc756564d3517f188",
72
+ reinterpret_cast<void*>(&pushy::jni_natives::InstallRecordSeal)},
73
+ {"2a05fbdca19f6d76363e1bf0d8b4", "723bfed0b88a274923311bb6e5a7826444205fcdf4daae943d432d07e18c93a9887e5a3655a2e4af83897d163a12fecae5b4705357351fae",
74
+ reinterpret_cast<void*>(&pushy::jni_natives::InstallRecordPromote)},
75
+ {"3802fad5a28e5b4d236d49aff9b5", "723bfed0b88a274923311bb6e5a7826444205fa8d2d1b98373002008e8c4ef8e8e655d3f09b0",
76
+ reinterpret_cast<void*>(&pushy::jni_natives::InstallRecordBundleSha256)},
77
+ }},
78
+ {"3919bbc3ab8a6b512c3e08f0c0b6df60452311edfbc8f780624b2d1de38c81af997f5d270bc7c1a88b8b6f", // ArchiveLimits
79
+ {
80
+ {"391ff1d2a5ae6651303619ea", "723dcffda48a7e446d331df7d1fca379582e0ae6a5e092ae580606",
81
+ reinterpret_cast<void*>(&pushy::jni_natives::ArchiveCheckEntries)},
82
+ {"2a1bf5df88996d40112f1dfad38382624822", "723ddefb84c2536f",
83
+ reinterpret_cast<void*>(&pushy::jni_natives::ArchivePlanFreeSpaceProbe)},
84
+ }},
85
+ };
86
+ return classes;
87
+ }
88
+
89
+ // Registers each method on its own: a host's R8 build may drop an unused
90
+ // class or native method, which must not prevent the rest from binding. A
91
+ // failure is still logged (release builds too): otherwise the first call of
92
+ // the unbound method surfaces as an UnsatisfiedLinkError with no hint why.
93
+ void RegisterAll(JNIEnv* env) {
94
+ for (const NativeClass& native_class : NativeClasses()) {
95
+ const std::string class_name = pushy::text::Reveal(native_class.name);
96
+ jclass clazz = env->FindClass(class_name.c_str());
97
+ if (clazz == nullptr) {
98
+ env->ExceptionClear();
99
+ PUSHY_JNI_LOGE("JNI binding: class %s not found, %zu native methods unbound",
100
+ class_name.c_str(), native_class.methods.size());
101
+ continue;
102
+ }
103
+ for (const NativeMethod& method : native_class.methods) {
104
+ const std::string name = pushy::text::Reveal(method.name);
105
+ const std::string signature = pushy::text::Reveal(method.signature);
106
+ const JNINativeMethod entry = {
107
+ const_cast<char*>(name.c_str()),
108
+ const_cast<char*>(signature.c_str()),
109
+ method.function,
110
+ };
111
+ if (env->RegisterNatives(clazz, &entry, 1) != JNI_OK) {
112
+ env->ExceptionClear();
113
+ PUSHY_JNI_LOGE("JNI binding: %s.%s%s could not be registered",
114
+ class_name.c_str(), name.c_str(), signature.c_str());
115
+ }
116
+ }
117
+ env->DeleteLocalRef(clazz);
118
+ }
119
+ }
120
+
121
+ } // namespace
122
+
123
+ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
124
+ JNIEnv* env = nullptr;
125
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
126
+ return JNI_ERR;
127
+ }
128
+ RegisterAll(env);
129
+ // Result classes and their field IDs are resolved once here; a failure is
130
+ // logged inside and makes the affected natives throw instead of guessing.
131
+ pushy::jni_natives::InitResultClassCache(env);
132
+ return JNI_VERSION_1_6;
133
+ }
@@ -0,0 +1,160 @@
1
+ #pragma once
2
+
3
+ #include <jni.h>
4
+
5
+ #include <cstdint>
6
+ #include <exception>
7
+ #include <limits>
8
+ #include <string>
9
+ #include <utility>
10
+ #include <vector>
11
+
12
+ // Small JNI helpers shared by every Android glue translation unit
13
+ // (update_core_android.cpp and update_flow_jni.cpp). Header-only with inline
14
+ // linkage so each can include it without a separate compilation unit.
15
+
16
+ namespace pushy {
17
+ namespace jni_util {
18
+
19
+ inline std::string JStringToString(JNIEnv* env, jstring value) {
20
+ if (value == nullptr) {
21
+ return std::string();
22
+ }
23
+
24
+ const char* chars = env->GetStringUTFChars(value, nullptr);
25
+ if (chars == nullptr) {
26
+ return std::string();
27
+ }
28
+
29
+ std::string result(chars);
30
+ env->ReleaseStringUTFChars(value, chars);
31
+ return result;
32
+ }
33
+
34
+ // Standard UTF-8 -> Java string. NewStringUTF expects JNI's *modified* UTF-8
35
+ // and corrupts supplementary code points (4-byte sequences, e.g. emoji), so
36
+ // decode explicitly and pass UTF-16 code units to NewString. Encoded
37
+ // surrogate code points are accepted too: strings that originated in Java may
38
+ // have entered through modified UTF-8 (JStringToString). Invalid bytes become
39
+ // U+FFFD. Returns nullptr when the result would not fit a jsize.
40
+ inline jstring ToJString(JNIEnv* env, const std::string& value) {
41
+ std::vector<jchar> utf16;
42
+ utf16.reserve(value.size());
43
+ size_t i = 0;
44
+ while (i < value.size()) {
45
+ const unsigned char first = static_cast<unsigned char>(value[i]);
46
+ uint32_t codePoint = 0xfffd;
47
+ size_t width = 1;
48
+ if (first < 0x80) {
49
+ codePoint = first;
50
+ } else if (first >= 0xc2 && first <= 0xdf && i + 1 < value.size()) {
51
+ const unsigned char b1 = static_cast<unsigned char>(value[i + 1]);
52
+ if ((b1 & 0xc0) == 0x80) {
53
+ codePoint = ((first & 0x1f) << 6) | (b1 & 0x3f);
54
+ width = 2;
55
+ }
56
+ } else if (first == 0xc0 && i + 1 < value.size() &&
57
+ static_cast<unsigned char>(value[i + 1]) == 0x80) {
58
+ codePoint = 0; // modified UTF-8 encoding of U+0000
59
+ width = 2;
60
+ } else if (first >= 0xe0 && first <= 0xef && i + 2 < value.size()) {
61
+ const unsigned char b1 = static_cast<unsigned char>(value[i + 1]);
62
+ const unsigned char b2 = static_cast<unsigned char>(value[i + 2]);
63
+ if ((b1 & 0xc0) == 0x80 && (b2 & 0xc0) == 0x80 &&
64
+ !(first == 0xe0 && b1 < 0xa0)) {
65
+ codePoint = ((first & 0x0f) << 12) | ((b1 & 0x3f) << 6) |
66
+ (b2 & 0x3f);
67
+ width = 3;
68
+ }
69
+ } else if (first >= 0xf0 && first <= 0xf4 && i + 3 < value.size()) {
70
+ const unsigned char b1 = static_cast<unsigned char>(value[i + 1]);
71
+ const unsigned char b2 = static_cast<unsigned char>(value[i + 2]);
72
+ const unsigned char b3 = static_cast<unsigned char>(value[i + 3]);
73
+ if ((b1 & 0xc0) == 0x80 && (b2 & 0xc0) == 0x80 &&
74
+ (b3 & 0xc0) == 0x80 && !(first == 0xf0 && b1 < 0x90) &&
75
+ !(first == 0xf4 && b1 > 0x8f)) {
76
+ codePoint = ((first & 0x07) << 18) | ((b1 & 0x3f) << 12) |
77
+ ((b2 & 0x3f) << 6) | (b3 & 0x3f);
78
+ width = 4;
79
+ }
80
+ }
81
+ i += width;
82
+ if (codePoint <= 0xffff) {
83
+ utf16.push_back(static_cast<jchar>(codePoint));
84
+ } else {
85
+ codePoint -= 0x10000;
86
+ utf16.push_back(static_cast<jchar>(0xd800 + (codePoint >> 10)));
87
+ utf16.push_back(static_cast<jchar>(0xdc00 + (codePoint & 0x3ff)));
88
+ }
89
+ }
90
+ if (utf16.size() > static_cast<size_t>(std::numeric_limits<jsize>::max())) {
91
+ return nullptr;
92
+ }
93
+ return env->NewString(utf16.empty() ? nullptr : utf16.data(),
94
+ static_cast<jsize>(utf16.size()));
95
+ }
96
+
97
+ inline std::vector<std::string> JArrayToVector(
98
+ JNIEnv* env,
99
+ jobjectArray values) {
100
+ std::vector<std::string> result;
101
+ if (values == nullptr) {
102
+ return result;
103
+ }
104
+
105
+ const jsize size = env->GetArrayLength(values);
106
+ result.reserve(static_cast<size_t>(size));
107
+ for (jsize index = 0; index < size; ++index) {
108
+ auto* item = static_cast<jstring>(env->GetObjectArrayElement(values, index));
109
+ result.push_back(JStringToString(env, item));
110
+ env->DeleteLocalRef(item);
111
+ }
112
+ return result;
113
+ }
114
+
115
+ inline void ThrowRuntimeException(JNIEnv* env, const char* message) {
116
+ jclass exception = env->FindClass("java/lang/RuntimeException");
117
+ if (exception != nullptr) {
118
+ env->ThrowNew(exception, message);
119
+ }
120
+ }
121
+
122
+ inline void ThrowRuntimeException(JNIEnv* env, const std::string& message) {
123
+ ThrowRuntimeException(env, message.c_str());
124
+ }
125
+
126
+ // The bytes of a Java byte[] as-is (an empty string for null).
127
+ inline std::string JByteArrayToString(JNIEnv* env, jbyteArray values) {
128
+ if (values == nullptr) {
129
+ return std::string();
130
+ }
131
+ const jsize size = env->GetArrayLength(values);
132
+ std::string result(static_cast<size_t>(size), '\0');
133
+ if (size > 0) {
134
+ env->GetByteArrayRegion(values, 0, size,
135
+ reinterpret_cast<jbyte*>(&result[0]));
136
+ }
137
+ return result;
138
+ }
139
+
140
+ // Runs a native method body so no C++ exception (bad_alloc/length_error from
141
+ // input-proportional STL allocations) ever unwinds through the JNI boundary:
142
+ // it becomes a Java RuntimeException like every other failure of the entry
143
+ // point, carrying `fallback_message` when the exception has no message of its
144
+ // own. Returns a value-initialized Result (nullptr / void) in that case.
145
+ template <typename Body>
146
+ auto GuardJni(JNIEnv* env, const char* fallback_message, Body&& body)
147
+ -> decltype(body()) {
148
+ using Result = decltype(body());
149
+ try {
150
+ return std::forward<Body>(body)();
151
+ } catch (const std::exception& error) {
152
+ ThrowRuntimeException(env, error.what());
153
+ } catch (...) {
154
+ ThrowRuntimeException(env, fallback_message);
155
+ }
156
+ return Result();
157
+ }
158
+
159
+ } // namespace jni_util
160
+ } // namespace pushy