Skip to content

Add androidNative targets.#1739

Open
MohammedKHC wants to merge 5 commits intosquare:masterfrom
MohammedKHC:android-native
Open

Add androidNative targets.#1739
MohammedKHC wants to merge 5 commits intosquare:masterfrom
MohammedKHC:android-native

Conversation

@MohammedKHC
Copy link
Contributor

@MohammedKHC MohammedKHC commented Nov 15, 2025

This adds support for androidNative targets.

This is the second attempt at trying to do this. Now I can confirm that it does compile and work.

The problem with the first attempt (#1726) was that it didn't account for the fact that platform.posix.DIR doesn't exist on androidNative. Therefore, opendir, readdir, and closedir can't be used from common code. This fixes this by using expect/actual for all this stuff.

To run the tests. Run the following commands in order.
(You need to have an Android Emulator running first.)

./gradlew androidNativeX64TestBinaries
adb push /path/to/okio/okio/build/bin/androidNativeX64/debugTest/test.kexe /data/local/tmp
rm -r /path/to/okio/build
adb push /path/to/okio /data/local/tmp/okio
adb shell
export OKIO_ROOT=/data/local/tmp/okio
/data/local/tmp/test.kexe

Closes: #1692, Closes #1242

@MohammedKHC
Copy link
Contributor Author

MohammedKHC commented Nov 15, 2025

Outdated.. To run the tests on the Android Emulator run ``` ./gradlew androidNativeX64TestBinaries && adb push okio/build/bin/androidNativeX64/debugTest/test.kexe /data/local/tmp && adb shell /data/local/tmp/test.kexe ```

For me all the tests passed except those:

[  FAILED  ] 23 tests, listed below:
[  FAILED  ] okio.NativeSystemFileSystemTest.listOnRelativePathWhichIsNotDotReturnsRelativePaths
[  FAILED  ] okio.NativeSystemFileSystemTest.listOrNullOnRelativePathWhichIsNotDotReturnsRelativePaths
[  FAILED  ] okio.ZipFileSystemGoTest.timeWinzip
[  FAILED  ] okio.ZipFileSystemTest.emptyZip
[  FAILED  ] okio.ZipFileSystemTest.emptyZipWithPrependedData
[  FAILED  ] okio.ZipFileSystemTest.zipWithFiles
[  FAILED  ] okio.ZipFileSystemTest.zipWithDeflate
[  FAILED  ] okio.ZipFileSystemTest.zipWithStore
[  FAILED  ] okio.ZipFileSystemTest.zipWithFileComments
[  FAILED  ] okio.ZipFileSystemTest.zipWithFileModifiedDate
[  FAILED  ] okio.ZipFileSystemTest.zipWithFileOutOfBoundsModifiedDate
[  FAILED  ] okio.ZipFileSystemTest.zipWithDirectoryModifiedDate
[  FAILED  ] okio.ZipFileSystemTest.zipWithModifiedDate
[  FAILED  ] okio.ZipFileSystemTest.zipWithEmptyDirectory
[  FAILED  ] okio.ZipFileSystemTest.zipWithSyntheticDirectory
[  FAILED  ] okio.ZipFileSystemTest.zip64
[  FAILED  ] okio.ZipFileSystemTest.zipWithArchiveComment
[  FAILED  ] okio.ZipFileSystemTest.cannotReadZipWithSpanning
[  FAILED  ] okio.ZipFileSystemTest.cannotReadZipWithEncryption
[  FAILED  ] okio.ZipFileSystemTest.zipTooShort
[  FAILED  ] okio.ZipFileSystemTest.filesOverlap
[  FAILED  ] okio.ZipFileSystemTest.canonicalizationValid
[  FAILED  ] okio.ZipFileSystemTest.canonicalizationInvalidThrows

Will investigate further and update you.

@MohammedKHC
Copy link
Contributor Author

MohammedKHC commented Nov 15, 2025

Also, Outdated UPDATE: I got most tests running. Those are the only failing tests. ``` [ FAILED ] 3 tests, listed below: [ FAILED ] okio.NativeSystemFileSystemTest.canonicalizeDotReturnsCurrentWorkingDirectory [ FAILED ] okio.NativeSystemFileSystemTest.listOnRelativePathWhichIsNotDotReturnsRelativePaths [ FAILED ] okio.NativeSystemFileSystemTest.listOrNullOnRelativePathWhichIsNotDotReturnsRelativePaths ```

To run tests now, do the following on the terminal.

./gradlew androidNativeX64TestBinaries
adb push /path/to/okio/okio/build/bin/androidNativeX64/debugTest/test.kexe /data/local/tmp
rm -r /path/to/okio/build
adb push /path/to/okio /data/local/tmp/okio
adb shell
cd /data/local/tmp
export OKIO_ROOT=/data/local/tmp/okio
./test.kexe

@MohammedKHC
Copy link
Contributor Author

MohammedKHC commented Nov 15, 2025

UPDATE again.
canonicalizeDotReturnsCurrentWorkingDirectory fails because i changed the cwd to /data/local/tmp..
The test expects it to be "/". And it does not fail if i don't do the cd.

Now the only failling tests are listOnRelativePathWhichIsNotDotReturnsRelativePaths and listOrNullOnRelativePathWhichIsNotDotReturnsRelativePaths

Best way to run the tests as of now.

./gradlew androidNativeX64TestBinaries
adb push /path/to/okio/okio/build/bin/androidNativeX64/debugTest/test.kexe /data/local/tmp
rm -r /path/to/okio/build
adb push /path/to/okio /data/local/tmp/okio
adb shell
export OKIO_ROOT=/data/local/tmp/okio
/data/local/tmp/test.kexe

@MohammedKHC
Copy link
Contributor Author

After reading the listOnRelativePathWhichIsNotDotReturnsRelativePaths code, it seems that the test itself is flaky. It only creates the required okio.api test file when one of the following is true:
isFakeFileSystem || isWrappingJimFileSystem || isWasiFileSystem

Knowing that, I can say that Okio does work as intended on Android native, which is useful for a bunch of Android tech apps such as Termux or Android IDEs.

@MohammedKHC
Copy link
Contributor Author

@JakeWharton should i edit listOnRelativePathWhichIsNotDotReturnsRelativePaths test or just ignore it on Android.
And do you think that the approach of using actual/expect is fine with opendir and this stuff?
Maybe there might be a better way?

@MohammedKHC
Copy link
Contributor Author

@JakeWharton are you free to look at this?

I think there are two ways to make opendir/closedir and this stuff on Android native

  1. Use expect/actual with a typealias and top level functions.
  2. Use expect/actual class with a name like DirEntry or something

And also it would be nice if we could create a new nativeNonAndroid sourceset. Although if we made it then we can't use the option 1, as the platform.posix.DIR is a typealias on Linux and we can't create a typealias to a typealias.
And this would kina complicate the targets hierarchy.

All the tests succeeded expect listOnRelativePathWhichIsNotDotReturnsRelativePaths and listOrNullOnRelativePathWhichIsNotDotReturnsRelativePaths

I can probably fix this tests and edit the github workflow to run them all for androidNative.

What do you think?

Info:
I really need this to be merged as I plan to use it in my
Rustroid Rust IDE (Iam writing some native tool that should run on it in Kotlin)

@MohammedKHC
Copy link
Contributor Author

@JakeWharton any update on this one?
I can fix the tests. And run the tests on the Android emulator (on CI), if you want to.

@JakeWharton
Copy link
Collaborator

Nope. I'm not working right now, so probably won't be looking at this for a month or two.

Copy link
Collaborator

@swankjesse swankjesse left a comment

Choose a reason for hiding this comment

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

Looks very promising. Thanks for driving this.

I wanna look into making androidNativeMain a child of linuxMain

@MohammedKHC
Copy link
Contributor Author

@swankjesse I tried another approach on the latest commit. Can you review it and tell me what do you think?
Now androidNative is a child of linux. and there is no code duplication. But androidNative now contains what I would call a workaround to platform.posix.DIR..

@MohammedKHC
Copy link
Contributor Author

Oops looks like the workaround didn't work on CI..
Although I am sure that this worked on my Linux machine.. will investigate more..

internal expect class PosixDirectory(path: Path): Closeable {
val isInvalid: Boolean
fun nextEntry(): CPointer<dirent>?
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the cleanest working approach so far.
I probably should’ve marked this PR as a draft from the beginning…

Man, everything feels way more complicated than it needs to be.

Why doesn’t platform.posix just expose DIR on Android?!

Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems like these should all be value classes to avoid the memory allocation. Does anything prevent that?

Copy link
Contributor Author

@MohammedKHC MohammedKHC Feb 11, 2026

Choose a reason for hiding this comment

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

@JakeWharton
The problem is that the actual implementation needs to store

private val dir = opendir(path.toString())

And if you meant that the value should be DIR. Then this is kinda complicated.
as we cannot use expect/actual for DIR in only two source sets. (androidNative, nativeNonAndroid)

that's because this code will not compile under nativeNonAndroid

actual typealias DIR = platform.posix.DIR

It will fail with an error cannot create a typealias to a typealias.
As platform.posix.DIR is a typealias on Linux.

we could create a new nativeNonLinux source set that will exclude androidNative and linux.

What do you think?

EDIT: I just realized that we could do this

internal expect value class PosixDirectory(private val dir: COpaquePointer) : Closeable {
  fun nextEntry(): CPointer<dirent>?
  override fun close()
}

internal expect fun openPosixDirectory(path: Path): PosixDirectory?

and

internal actual value class PosixDirectory(private val dir: COpaquePointer) : Closeable {
  actual fun nextEntry() = readdir(dir.reinterpret())
  actual override fun close() {
    closedir(dir.reinterpret()) // Ignore errno from closedir.
  }
}

internal actual fun openPosixDirectory(path: Path): PosixDirectory? {
  return opendir(path.toString())?.let(::PosixDirectory)
}

Does this seem good?
And also we can make openPosixDirectory inline.
Do you think it's worth it?
And btw, I really hate the Kotlin compiler advising me to not use inline on functions..

@MohammedKHC MohammedKHC force-pushed the android-native branch 2 times, most recently from c1d512a to 4fb4578 Compare February 9, 2026 12:51
and workaround `platform.posix.DIR` not being available there.
…ons.

Unfortunately we cannot typealias `DIR` in a shared source set. Because it is already a typealias on Linux.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for androidNativeX64 and androidNativeArm64 targets Consider supporting all official K/N targets

3 participants