Skip to content

Revert "[path_provider_android] Changes internal implementation to use JNI"#11453

Draft
Renzo-Olivares wants to merge 3 commits intomainfrom
revert-9770-pp_jnigen
Draft

Revert "[path_provider_android] Changes internal implementation to use JNI"#11453
Renzo-Olivares wants to merge 3 commits intomainfrom
revert-9770-pp_jnigen

Conversation

@Renzo-Olivares
Copy link
Copy Markdown
Contributor

@Renzo-Olivares Renzo-Olivares commented Apr 6, 2026

Reverts #9770

Reason: Fix flutter/flutter tree

Tracking issue: flutter/flutter#184689

Crash below:

https://logs.chromium.org/logs/flutter/buildbucket/cr-buildbucket/8685239933882993057/+/u/run_test.dart_for_tool_tests_commands_shard_and_subshard_1_1/stdout

'package:flutter_tools/src/platform_plugins.dart': Failed assertion: line 444 pos 15: 'pluginClass != null || dartPluginClass != null || defaultPackage != null': is not true.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request reverts the path_provider_android implementation from JNI/FFI to a Pigeon-based architecture, including a version downgrade to 2.2.23 and the removal of JNI dependencies. Feedback highlights a non-existent Android Gradle Plugin version and multiple potential NullPointerException vulnerabilities in the PathProviderPlugin Java code, particularly concerning Context usage and directory access. A suggestion to clear the context reference on engine detachment was also provided.

}

dependencies {
classpath("com.android.tools.build:gradle:8.13.1")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The Android Gradle Plugin version 8.13.1 appears to be a typo, as this version does not exist in the Google Maven repository. It is likely intended to be 8.1.3, 8.3.1, or another valid version compatible with the project's Gradle configuration.

Comment on lines +26 to +34
private void setUp(BinaryMessenger messenger, Context context) {
try {
PathProviderApi.setUp(messenger, this);
} catch (Exception ex) {
Log.e(TAG, "Received exception while setting up PathProviderPlugin", ex);
}

this.context = context;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The context field should be initialized before calling PathProviderApi.setUp. If a message is received from the Flutter side immediately after the API is set up but before the context is assigned, it could lead to a NullPointerException in the handler methods.

  private void setUp(BinaryMessenger messenger, Context context) {
    this.context = context;
    try {
      PathProviderApi.setUp(messenger, this);
    } catch (Exception ex) {
      Log.e(TAG, "Received exception while setting up PathProviderPlugin", ex);
    }
  }

Comment on lines +42 to +44
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
PathProviderApi.setUp(binding.getBinaryMessenger(), null);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

It is good practice to null out the context reference when the plugin is detached from the engine to avoid holding onto the application context longer than necessary, even though getApplicationContext() is generally safe.

Suggested change
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
PathProviderApi.setUp(binding.getBinaryMessenger(), null);
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
PathProviderApi.setUp(binding.getBinaryMessenger(), null);
context = null;
}


@Override
public @Nullable String getTemporaryPath() {
return context.getCacheDir().getPath();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

context.getCacheDir() can return null if the cache directory does not exist and cannot be created (e.g., due to storage issues). A null check should be added to prevent a NullPointerException when calling .getPath().

    File cacheDir = context.getCacheDir();
    return cacheDir == null ? null : cacheDir.getPath();


@Override
public @Nullable String getApplicationCachePath() {
return context.getCacheDir().getPath();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Similar to getTemporaryPath, context.getCacheDir() can return null. Adding a null check here ensures robustness.

    File cacheDir = context.getCacheDir();
    return cacheDir == null ? null : cacheDir.getPath();

Comment on lines +78 to +82
for (File dir : context.getExternalCacheDirs()) {
if (dir != null) {
paths.add(dir.getAbsolutePath());
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

context.getExternalCacheDirs() can return null if the shared/external storage is not currently available. Iterating over a null array will result in a crash.

    File[] dirs = context.getExternalCacheDirs();
    if (dirs != null) {
      for (File dir : dirs) {
        if (dir != null) {
          paths.add(dir.getAbsolutePath());
        }
      }
    }

Comment on lines +90 to +94
for (File dir : context.getExternalFilesDirs(getStorageDirectoryString(directory))) {
if (dir != null) {
paths.add(dir.getAbsolutePath());
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

context.getExternalFilesDirs() can return null if the storage is unavailable. A null check should be performed before iterating over the results.

    File[] dirs = context.getExternalFilesDirs(getStorageDirectoryString(directory));
    if (dirs != null) {
      for (File dir : dirs) {
        if (dir != null) {
          paths.add(dir.getAbsolutePath());
        }
      }
    }

@hellohuanlin
Copy link
Copy Markdown
Contributor

hellohuanlin commented Apr 6, 2026

I wonder how the versioning works? Was the previous PR published already (it has a version bump).

I'm also curious if the original PR will cause the same crash for plugin users.

@jmagman
Copy link
Copy Markdown
Member

jmagman commented Apr 6, 2026

I wonder how the versioning works? Was the previous PR published already (it has a version bump).

This won't unpublish the package. You would need to bump the version. Technically you can unpublish a pub package but I'm not sure the process for that. @stuartmorgan-g would know. Generally we don't do it.

@bparrishMines
Copy link
Copy Markdown
Contributor

cc @liamappelbe

@bparrishMines
Copy link
Copy Markdown
Contributor

If possible the flutter/flutter repo may need to set path_provider_android: 2.2.23 temporarily. I'm assuming Flutter is using the latest version from pub.dev.

@jmagman
Copy link
Copy Markdown
Member

jmagman commented Apr 6, 2026

If possible the flutter/flutter repo may need to set path_provider_android: 2.2.23 temporarily. I'm assuming Flutter is using the latest version from pub.dev.

I was trying to do that here, but I'm still hitting test failures. I wasn't able to reproduce them locally. flutter/flutter#184688

@jmagman jmagman added the CICD Run CI/CD label Apr 6, 2026
@Renzo-Olivares
Copy link
Copy Markdown
Contributor Author

I'm also trying updating the assert we are hitting, it looks like it might just be an oversight that we are hitting this crash but I don't have enough context flutter/flutter#184695.

the ffiPlugin flag was added in flutter/flutter#96225 , but it was not added to assert of WindowsPlugin for some reason (it was added to the assert of LinuxPlugin).

@stuartmorgan-g
Copy link
Copy Markdown
Collaborator

Since so far the issues are specific to our CI I would rather we avoid a full revert cycle if possible. I have unpublished 2.3.0 from pub.dev temporarily while we work on fixes to our systems; it looks like flutter/flutter already had a real fix landed, and I should be able to fix flutter/packages today, and then undo the unpublshing to check that everything is good without doing full revert/reland cycles.

(If we do revert, we should not revert the changes outside of the package itself, as it causes a ton more CI runs and potential flake)

@stuartmorgan-g stuartmorgan-g marked this pull request as draft April 7, 2026 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants