Skip to content

On Android, set dynamic code files to readonly #1430

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

Merged
merged 5 commits into from
Sep 11, 2023
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
26 changes: 26 additions & 0 deletions app/src/util_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1587,12 +1587,33 @@ const std::vector<internal::EmbeddedFile>& CacheEmbeddedFiles(
file::GetClass(), file::GetMethodId(file::kConstructorFilePath),
cache_dir, filename);
env->DeleteLocalRef(filename);
CheckAndClearJniExceptions(env);
// Below, we would have set the file read only on a previous run. Here, set
// it to writable and then delete it before creating it again.
//
// if output_file.exists() {
if (env->CallBooleanMethod(output_file, file::GetMethodId(file::kExists))) {
CheckAndClearJniExceptions(env);
// output_file.setWritable(true);
env->CallBooleanMethod(output_file, file::GetMethodId(file::kSetWritable),
JNI_TRUE);
CheckAndClearJniExceptions(env);
// output_file.delete();
env->CallBooleanMethod(output_file, file::GetMethodId(file::kDelete));
CheckAndClearJniExceptions(env);
}
jobject output_stream = env->NewObject(
file_output_stream::GetClass(),
file_output_stream::GetMethodId(file_output_stream::kConstructorFile),
output_file);
bool failed = CheckAndClearJniExceptions(env);
if (!failed) {
// Android 14 requires that we set the open dex file to readonly BEFORE
// writing code to it.
jboolean did_set_readonly = env->CallBooleanMethod(
output_file, file::GetMethodId(file::kSetReadOnly));
// If it failed, move on and try again later after closing the file.
if (CheckAndClearJniExceptions(env)) did_set_readonly = JNI_FALSE;
jobject output_array = env->NewByteArray(it->size);
env->SetByteArrayRegion(static_cast<jbyteArray>(output_array), 0,
it->size,
Expand All @@ -1605,6 +1626,11 @@ const std::vector<internal::EmbeddedFile>& CacheEmbeddedFiles(
env->CallVoidMethod(output_stream, file_output_stream::GetMethodId(
file_output_stream::kClose));
failed |= CheckAndClearJniExceptions(env);
if (!did_set_readonly) {
env->CallBooleanMethod(output_file,
file::GetMethodId(file::kSetReadOnly));
util::CheckAndClearJniExceptions(env);
}
env->DeleteLocalRef(output_array);
env->DeleteLocalRef(output_stream);
}
Expand Down
4 changes: 4 additions & 0 deletions app/src/util_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,10 @@ METHOD_LOOKUP_DECLARATION(intent, INTENT_METHODS);
X(ConstructorFilePath, "<init>", "(Ljava/io/File;Ljava/lang/String;)V"), \
X(GetAbsolutePath, "getAbsolutePath", "()Ljava/lang/String;"), \
X(GetPath, "getPath", "()Ljava/lang/String;"), \
X(Exists, "exists", "()Z"), \
X(Delete, "delete", "()Z"), \
X(SetReadOnly, "setReadOnly", "()Z"), \
X(SetWritable, "setWritable", "(Z)Z"), \
X(ToUri, "toURI", "()Ljava/net/URI;")
// clang-format on
METHOD_LOOKUP_DECLARATION(file, FILE_METHODS)
Expand Down
2 changes: 2 additions & 0 deletions release_build_files/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,8 @@ code.
## Release Notes
### Next Release
- Changes
- General (Android): Made dynamic code files read only to comply with new
Android 14 security requirements. This fixes a crash at API level 34+.
- Analytics (iOS): Added InitiateOnDeviceConversionMeasurementWithPhoneNumber
function to facilitate the [on-device conversion
measurement](https://support.google.com/google-ads/answer/12119136) API.
Expand Down