Skip to content

Implement ObjectArena and ArenaRef to solve JNI Global Reference Issue#1176

Closed
cherylEnkidu wants to merge 17 commits intomainfrom
cheryllin/AndroidJNI2
Closed

Implement ObjectArena and ArenaRef to solve JNI Global Reference Issue#1176
cherylEnkidu wants to merge 17 commits intomainfrom
cheryllin/AndroidJNI2

Conversation

@cherylEnkidu
Copy link
Copy Markdown
Contributor

Description

Implemented ArenaRef which uses as a replacement of Global Reference in order to solve problems caused by JNI Global Reference limitation.


Testing

Integration tests


Type of Change

Place an x the applicable box:

  • Bug fix. (#569)(#1193)
  • New feature. A non-breaking change which adds functionality.
  • Other, such as a build process or documentation change.

Notes

  • Bug fixes and feature changes require an update to the Release Notes section of release_build_files/readme.md.
  • Read the contribution guidelines CONTRIBUTING.md.
  • Changes to the public API require an internal API review. If you'd like to help us make Firebase APIs better, please propose your change in a feature request so that we can discuss it together.

@cherylEnkidu cherylEnkidu self-assigned this Dec 25, 2022
@cherylEnkidu cherylEnkidu added skip-release-notes Skip release notes check tests-requested: quick Trigger a quick set of integration tests. labels Dec 25, 2022
@github-actions github-actions bot added tests: in-progress This PR's integration tests are in progress. and removed tests-requested: quick Trigger a quick set of integration tests. labels Dec 25, 2022
@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 25, 2022

Integration test with FLAKINESS (succeeded after retry)

Requested by @cherylEnkidu on commit 2ce5b8d
Last updated: Sun Dec 25 09:59 PST 2022
View integration test log & download artifacts

Failures Configs
firestore [TEST] [FLAKINESS] [Android] [1/3 os: windows] [1/2 android_device: android_target]
(1 failed tests)  CRASH/TIMEOUT

Add flaky tests to go/fpl-cpp-flake-tracker

@cherylEnkidu cherylEnkidu added tests-requested: quick Trigger a quick set of integration tests. and removed tests: in-progress This PR's integration tests are in progress. labels Dec 25, 2022
@github-actions github-actions bot added tests: in-progress This PR's integration tests are in progress. tests: failed This PR's integration tests failed. and removed tests-requested: quick Trigger a quick set of integration tests. labels Dec 25, 2022
@firebase-workflow-trigger firebase-workflow-trigger bot removed the tests: in-progress This PR's integration tests are in progress. label Dec 25, 2022
@github-actions github-actions bot added the tests: succeeded This PR's integration tests succeeded. label Dec 25, 2022
@cherylEnkidu cherylEnkidu added tests-requested: quick Trigger a quick set of integration tests. and removed tests: succeeded This PR's integration tests succeeded. tests: failed This PR's integration tests failed. labels Dec 29, 2022
@github-actions github-actions bot added tests: in-progress This PR's integration tests are in progress. and removed tests-requested: quick Trigger a quick set of integration tests. labels Dec 29, 2022
@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 29, 2022

✅  Integration test succeeded!

Requested by @cherylEnkidu on commit 7889019
Last updated: Sun Feb 12 19:20 PST 2023
View integration test log & download artifacts

@github-actions github-actions bot added the tests: failed This PR's integration tests failed. label Dec 29, 2022
@firebase-workflow-trigger firebase-workflow-trigger bot removed the tests: in-progress This PR's integration tests are in progress. label Dec 29, 2022
@dconeybe dconeybe added tests-requested: quick Trigger a quick set of integration tests. and removed tests: failed This PR's integration tests failed. labels Jan 3, 2023
@github-actions github-actions bot added tests: succeeded This PR's integration tests succeeded. and removed tests-requested: quick Trigger a quick set of integration tests. labels Jan 12, 2023
@firebase-workflow-trigger firebase-workflow-trigger bot removed the tests: in-progress This PR's integration tests are in progress. label Jan 12, 2023
@dconeybe
Copy link
Copy Markdown
Contributor

I just realized something: the ArenaRef has a concurrency bug. If ArenaRefs are created/copied concurrently from multiple threads then there is a race condition that will cause bugs. This is because the multiple threads can be accessing the Java HashMap at the same time without any synchronization. This leads to undefined behavior, and could be causing that weird bug you're seeing in CI that you can't reproduce locally. One fix would be to protect gArenaRefHashMap with an std::mutex.

@cherylEnkidu cherylEnkidu added tests-requested: quick Trigger a quick set of integration tests. and removed tests: succeeded This PR's integration tests succeeded. labels Jan 18, 2023
@github-actions github-actions bot added tests: in-progress This PR's integration tests are in progress. tests: failed This PR's integration tests failed. and removed tests-requested: quick Trigger a quick set of integration tests. labels Jan 18, 2023
@firebase-workflow-trigger firebase-workflow-trigger bot removed the tests: in-progress This PR's integration tests are in progress. label Jan 18, 2023
@cherylEnkidu cherylEnkidu force-pushed the cheryllin/AndroidJNI2 branch from 4c9e2a6 to 54c0826 Compare January 19, 2023 08:54
@awais-100
Copy link
Copy Markdown

Any update, please? Games crash rates are too high due to this issue, and Play Console's bad behavior threshold is crossed.

@dconeybe
Copy link
Copy Markdown
Contributor

dconeybe commented Feb 6, 2023

Any update, please? Games crash rates are too high due to this issue, and Play Console's bad behavior threshold is crossed.

Please see firebase/firebase-unity-sdk#569. tl;dr The fix is not yet ready but we'll let you know when it is.


ArenaRef& ArenaRef::operator=(ArenaRef&& other) {
if (this != &other) {
std::swap(key_, other.key_);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do the using std::swap thing here in the move assignment operator, just like you did for the move constructor (#1176 (comment))

EXPECT_EQ("Foo", result);
}

TEST_F(EnvTest, IsInstanceOfChecksValidArenaRef) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Augment the IsInstanceOfChecksValidArenaRef test to also call IsInstanceOf with a different class (e.g. java.lang.Integer) such that it returns false.

// clang-format on
}

TEST_F(FieldValueTest, TestArenaRefMinimunLimit) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment to TestArenaRefMinimunLimit to mention the global refs issue that it's checking and include a link to the issue that it's verifying doesn't regress (i.e. firebase/firebase-unity-sdk#569)

HashMap* gArenaRefHashMap = nullptr;
jclass gLongClass = nullptr;
jmethodID gLongConstructor = nullptr;
std::mutex mutex_;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Move std::mutex mutex_ to be defined above the variable that it is protecting (i.e. above the definition of gArenaRefHashMap). Although it's not super relevant in this case, you always want to make sure that the mutex outlives the variable(s) that it is protecting.

HashMap* gArenaRefHashMap = nullptr;
jclass gLongClass = nullptr;
jmethodID gLongConstructor = nullptr;
std::mutex mutex_;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename mutex_ to match the naming convention of global variables. Also name it to indicate which variable it is protecting. e.g. gArenaRefHashMapMutex.

jmethodID ctor =
env().GetMethodId(clazz, "<init>", "(Ljava/lang/String;)V");

Local<String> message = env().NewStringUtf("Testing throw");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just get rid of these throwException() and clearExceptionOccurred() helper methods.

throwException() can be replaced by

env.Throw(CreateException(env, "Test Exception"));

and clearExceptionOccurred() can be replaced by

env.ExceptionClear();

Admittedly, this leads to a tiny bit of code duplciation between test cases but that's acceptable because, IMO, it improves readabililty of the test cases.

See go/tott/598 about "DAMP" tests rather than the "DRY" principle that is common in non-testing code.

TEST_F(ArenaRefTestAndroid, MoveConstructsFromValid) {
Local<String> string = env().NewStringUtf("hello world");

ArenaRef arena_ref2(env(), string);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Rename arena_ref2 and arena_ref3 back to arena_ref1 and arena_ref2, respectively.


TEST_F(ArenaRefTestAndroid, ThrowBeforeConstruct) {
Local<String> string = env().NewStringUtf("hello world");
EXPECT_EQ(string.ToString(env()).size(), 11U);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove these checks for the length of the string returned from NewStringUtf(). You can just assume that this is true. Applies here and elsewhere in this file.

EXPECT_TRUE(env().IsSameObject(arena_ref1.get(env()), string1));
}

TEST_F(ArenaRefTestAndroid, ThrowBeforeConstruct) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can you rename the "ThrowBeforeXXX" test names to "XXXWithPendingException" or something like that? I think using the term "with pending exception" more clearly conveys what scenario the test is testing.

clearExceptionOccurred();
EXPECT_TRUE(env().IsSameObject(arena_ref2.get(env()), string));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test for calling get() with a pending exception.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

skip-release-notes Skip release notes check tests: succeeded This PR's integration tests succeeded.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants