1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Android: Fix ContentSharer crash on Android 14

This commit is contained in:
attila 2023-11-02 17:06:40 +01:00 committed by Attila Szarvas
parent fa0c91ddee
commit b800890ec6
2 changed files with 74 additions and 14 deletions

View file

@ -31,8 +31,15 @@ template <typename JavaType>
class LocalRef class LocalRef
{ {
public: public:
LocalRef() noexcept : obj (nullptr) {} LocalRef() noexcept = default;
explicit LocalRef (JavaType o) noexcept : obj (o) {}
/* This constructor must not be used to wrap local references that were not created through
JNI, i.e. for native function callback parameters.
*/
explicit LocalRef (JavaType o) noexcept
: LocalRef (o, false)
{}
LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {} LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {}
LocalRef (LocalRef&& other) noexcept : obj (nullptr) { std::swap (obj, other.obj); } LocalRef (LocalRef&& other) noexcept : obj (nullptr) { std::swap (obj, other.obj); }
~LocalRef() { clear(); } ~LocalRef() { clear(); }
@ -48,31 +55,83 @@ public:
LocalRef& operator= (const LocalRef& other) LocalRef& operator= (const LocalRef& other)
{ {
JavaType newObj = retain (other.obj); auto tmp = other;
clear(); std::swap (tmp.obj, obj);
obj = newObj;
return *this; return *this;
} }
LocalRef& operator= (LocalRef&& other) LocalRef& operator= (LocalRef&& other) noexcept
{ {
clear(); auto tmp = std::move (other);
std::swap (other.obj, obj); std::swap (tmp.obj, obj);
return *this; return *this;
} }
bool operator== (std::nullptr_t) const noexcept { return obj == nullptr; }
bool operator!= (std::nullptr_t) const noexcept { return obj != nullptr; }
operator JavaType() const noexcept { return obj; } operator JavaType() const noexcept { return obj; }
JavaType get() const noexcept { return obj; } JavaType get() const noexcept { return obj; }
private: auto release()
JavaType obj; {
return std::exchange (obj, nullptr);
}
/** Creates a new internal local reference. */
static auto addOwner (JavaType o)
{
return LocalRef { o, true };
}
/** Takes ownership of the passed in local reference, and deletes it when the LocalRef goes out
of scope.
*/
static auto becomeOwner (JavaType o)
{
return LocalRef { o, false };
}
private:
static JavaType retain (JavaType obj) static JavaType retain (JavaType obj)
{ {
return obj == nullptr ? nullptr : (JavaType) getEnv()->NewLocalRef (obj); return obj == nullptr ? nullptr : (JavaType) getEnv()->NewLocalRef (obj);
} }
/* We cannot delete local references that were not created by JNI, e.g. references that were
created by the VM and passed into the native function.
For these references we should use createNewLocalRef = true, which will create a new
local reference that this wrapper is allowed to delete.
Doing otherwise will result in an "Attempt to remove non-JNI local reference" warning in the
VM, which could even cause crashes in future VM implementations.
*/
LocalRef (JavaType o, bool createNewLocalRef) noexcept
: obj (createNewLocalRef ? retain (o) : o)
{}
JavaType obj = nullptr;
}; };
/* Creates a new local reference that shares ownership with the passed in pointer.
Can be used for wrapping function parameters that were created outside the JNI.
*/
template <class JavaType>
auto addLocalRefOwner (JavaType t)
{
return LocalRef<JavaType>::addOwner (t);
}
/* Wraps a local reference and destroys it when it goes out of scope. */
template <class JavaType>
auto becomeLocalRefOwner (JavaType t)
{
return LocalRef<JavaType>::becomeOwner (t);
}
//============================================================================== //==============================================================================
template <typename JavaType> template <typename JavaType>
class GlobalRefImpl class GlobalRefImpl
@ -846,7 +905,7 @@ namespace
javaString ("").get())); javaString ("").get()));
for (int i = 0; i < juceArray.size(); ++i) for (int i = 0; i < juceArray.size(); ++i)
env->SetObjectArrayElement (result, i, javaString (juceArray [i]).get()); env->SetObjectArrayElement (result.get(), i, javaString (juceArray [i]).get());
return result; return result;
} }

View file

@ -336,8 +336,8 @@ public:
static jobjectArray JNICALL contentSharerGetStreamTypes (JNIEnv*, jobject /*contentProvider*/, jobject uri, jstring mimeTypeFilter) static jobjectArray JNICALL contentSharerGetStreamTypes (JNIEnv*, jobject /*contentProvider*/, jobject uri, jstring mimeTypeFilter)
{ {
return getInstance().getStreamTypes (LocalRef<jobject> (static_cast<jobject> (uri)), return getInstance().getStreamTypes (addLocalRefOwner (uri),
LocalRef<jstring> (static_cast<jstring> (mimeTypeFilter))); addLocalRefOwner (mimeTypeFilter));
} }
private: private:
@ -482,7 +482,8 @@ private:
if (extension.isEmpty()) if (extension.isEmpty())
return nullptr; return nullptr;
return juceStringArrayToJava (filterMimeTypes (detail::MimeTypeTable::getMimeTypesForFileExtension (extension), juceString (mimeTypeFilter.get()))); return juceStringArrayToJava (filterMimeTypes (detail::MimeTypeTable::getMimeTypesForFileExtension (extension),
juceString (mimeTypeFilter.get()))).release();
} }
std::unique_ptr<ActivityLauncher> doIntent (const LocalRef<jobject>& intent, std::unique_ptr<ActivityLauncher> doIntent (const LocalRef<jobject>& intent,