Skip to content

Commit

Permalink
Android: less main thread io and mmap (#682)
Browse files Browse the repository at this point in the history
  • Loading branch information
clang-clang-clang authored Mar 13, 2024
1 parent 09dc5d8 commit aa4140d
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 42 deletions.
19 changes: 4 additions & 15 deletions librtt/Rtt_Archive.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is part of the Corona game engine.
// This file is part of the Solar2D game engine.
// With contributions from Dianchu Technology
// For overview and more information on licensing please refer to README.md
// Home page: https://github.com/coronalabs/corona
// Contact: [email protected]
Expand Down Expand Up @@ -31,6 +32,7 @@
static const unsigned S_IWUSR = _S_IWRITE; ///< write by user
#elif defined( Rtt_ANDROID_ENV )
#include "NativeToJavaBridge.h"
#include <sys/mman.h>
#else
#include <stdlib.h>
#include <unistd.h>
Expand Down Expand Up @@ -1009,19 +1011,6 @@ Archive::Archive( Rtt_Allocator& allocator, const char *srcPath )
}
Rtt_FileClose(filePointer);
}
#elif defined( Rtt_ANDROID_ENV )
bool ok = NativeToJavaBridge::GetRawAsset( srcPath, fBits );
if ( ok ) {
fData = fBits.Get();
fDataLen = fBits.Length();
}
#if Rtt_DEBUG_ARCHIVE
else
{
Rtt_TRACE( ( "[Archive::Archive] NativeToJavaBridge::GetRawAsset failed\n", fDataLen ) );
}
#endif

#else
int fileDescriptor = Rtt_FileDescriptorOpen(srcPath, O_RDONLY, S_IRUSR);
struct stat statbuf;
Expand Down Expand Up @@ -1107,7 +1096,7 @@ Archive::Archive( Rtt_Allocator& allocator, const char *srcPath )

Archive::~Archive()
{
#if defined( Rtt_ANDROID_ENV ) || defined( Rtt_EMSCRIPTEN_ENV ) || defined( Rtt_NXS_ENV )
#if defined( Rtt_EMSCRIPTEN_ENV ) || defined( Rtt_NXS_ENV )
// Do nothing.
#elif defined( Rtt_WIN_PHONE_ENV )
Rtt_FREE((void*)fData);
Expand Down
5 changes: 3 additions & 2 deletions librtt/Rtt_Archive.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is part of the Corona game engine.
// This file is part of the Solar2D game engine.
// With contributions from Dianchu Technology
// For overview and more information on licensing please refer to README.md
// Home page: https://github.com/coronalabs/corona
// Contact: [email protected]
Expand All @@ -12,7 +13,7 @@

#if !defined( Rtt_NO_ARCHIVE )
#include "Rtt_Lua.h"
#if defined( Rtt_ANDROID_ENV ) || defined( Rtt_EMSCRIPTEN_ENV )
#if defined( Rtt_EMSCRIPTEN_ENV )
#define Rtt_ARCHIVE_COPY_DATA 1
#endif
#endif
Expand Down
5 changes: 3 additions & 2 deletions librtt/Rtt_LuaProxyVTable.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is part of the Corona game engine.
// This file is part of the Solar2D game engine.
// With contributions from Dianchu Technology
// For overview and more information on licensing please refer to README.md
// Home page: https://github.com/coronalabs/corona
// Contact: [email protected]
Expand Down Expand Up @@ -3759,7 +3760,7 @@ LuaDisplayObjectProxyVTable::PushAndRemove( lua_State *L, GroupObject* parent, S
if ( stage )
{
Rtt_ASSERT( LuaContext::GetRuntime( L )->GetDisplay().HitTestOrphanage() != parent
|| LuaContext::GetRuntime( L )->GetDisplay().Orphanage() != parent );
&& LuaContext::GetRuntime( L )->GetDisplay().Orphanage() != parent );

SUMMED_TIMING( par1, "Object: PushAndRemove (release)" );

Expand Down
10 changes: 7 additions & 3 deletions librtt/Rtt_Runtime.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is part of the Corona game engine.
// This file is part of the Solar2D game engine.
// With contributions from Dianchu Technology
// For overview and more information on licensing please refer to README.md
// Home page: https://github.com/coronalabs/corona
// Contact: [email protected]
Expand Down Expand Up @@ -1208,8 +1209,11 @@ Runtime::LoadApplication( const LoadParameters& parameters )

// Use kSystemResourceDir b/c resource.car should always live inside the .app bundle
String filePath( GetAllocator() );

fPlatform.PathForFile( basename, MPlatform::kSystemResourceDir, MPlatform::kDefaultPathFlags, filePath );
#if defined( Rtt_ANDROID_ENV )
fPlatform.PathForFile( basename, MPlatform::kResourceDir, MPlatform::kDefaultPathFlags, filePath );
#else
fPlatform.PathForFile( basename, MPlatform::kSystemResourceDir, MPlatform::kDefaultPathFlags, filePath );
#endif

{
// Init VM
Expand Down
6 changes: 3 additions & 3 deletions platform/android/sdk/src/com/ansca/corona/CoronaActivity.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is part of the Corona game engine.
// This file is part of the Solar2D game engine.
// With contributions from Dianchu Technology
// For overview and more information on licensing please refer to README.md
// Home page: https://github.com/coronalabs/corona
// Contact: [email protected]
Expand Down Expand Up @@ -299,8 +300,7 @@ protected void onCreate(Bundle savedInstanceState) {
fController.setCoronaSystemApiListener(systemHandler);

// Attempt to load/reload this application's expansion files, if they exist.
com.ansca.corona.storage.FileServices fileServices = new com.ansca.corona.storage.FileServices(this);
fileServices.loadExpansionFiles();
com.ansca.corona.storage.FileServices.resetAccessedExpansionFileDirectory();

// Create and set up a store object used to manage in-app purchases.
myStore = new com.ansca.corona.purchasing.StoreProxy(fCoronaRuntime, fCoronaRuntime.getController());
Expand Down
60 changes: 43 additions & 17 deletions platform/android/sdk/src/com/ansca/corona/storage/FileServices.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// This file is part of the Corona game engine.
// This file is part of the Solar2D game engine.
// With contributions from Dianchu Technology
// For overview and more information on licensing please refer to README.md
// Home page: https://github.com/coronalabs/corona
// Contact: [email protected]
Expand Down Expand Up @@ -29,6 +30,10 @@ public class FileServices extends com.ansca.corona.ApplicationContextProvider {
/** Set to true if this application has attempted to load expansion files. */
private static boolean sHasAccessedExpansionFileDirectory = false;

public static void resetAccessedExpansionFileDirectory() {
sHasAccessedExpansionFileDirectory = false;
}

/** Stores the path to the "patch" expansion file for fast access. */
private static java.io.File sPatchExpansionFile = null;

Expand Down Expand Up @@ -749,6 +754,8 @@ public java.io.File extractAssetFile(java.io.File assetFile) {
* The file will be extracted to a hidden folder under the application's directory.
* <p>
* If the given file has already been extracted, then this method WILL attempt to extract it again
* <p>
* When a file copy fails, it is retried internally once.
* @param assetFile The asset file within the APK's assets directory or expansion files.
* @param overwrite Whether the file should be overwrite whats already extracted, if anything. True to overwrite.
* @return Returns an absolute path to where the asset file was copied to.
Expand Down Expand Up @@ -779,7 +786,9 @@ public java.io.File extractAssetFile(java.io.File assetFile, boolean overwrite)

// Extract the asset file and copy it to an external directory.
boolean wasCopied = copyFile(assetFile, destinationFile);
if (wasCopied == false) {
// There is a 0.3% chance of the file fails to be copied (AssetInputStream#read() returns -1 early),
// we need a reliable extracted, so try again here.
if (!wasCopied && !copyFile(assetFile, destinationFile)) {
return null;
}

Expand Down Expand Up @@ -943,6 +952,7 @@ public boolean copyFile(String sourceFilePath, String destinationFilePath) {
public boolean copyFile(java.io.File sourceFile, java.io.File destinationFile) {
java.io.InputStream inputStream = null;
java.io.FileOutputStream outputStream = null;
java.io.File tmpFile = null;
boolean hasSucceeded = false;

// Validate arguments.
Expand All @@ -962,23 +972,33 @@ public boolean copyFile(java.io.File sourceFile, java.io.File destinationFile) {
if (inputStream != null) {
// Create the destination directory tree, if it does not already exist. Only create it if its actually a resource file.
destinationFile.getParentFile().mkdirs();
outputStream = new java.io.FileOutputStream(destinationFile);

// Writes and renames temporary files to prevent incomplete copies.
tmpFile = java.io.File.createTempFile("copy-" + destinationFile.getName() + "-", null, destinationFile.getParentFile());
outputStream = new java.io.FileOutputStream(tmpFile);
if (outputStream != null) {
int byteCount = inputStream.available();
// openFile() returns AssetInputStream, ZipFileEntryInputStream, and so on,
// overrides available() to use ZipEntry to provide length.
final int byteCount = inputStream.available();

// Used for comparison to check if AssetInputStream#read() returns -1 early.
int readTotal = 0;

if (byteCount > 0) {
final int BUFFER_SIZE = byteCount > BUFFER_SIZE_THRESHOLD ? BUFFER_SIZE_LARGE_IO : BUFFER_SIZE_NORMAL;
byte[] byteBuffer = new byte[BUFFER_SIZE];
while (byteCount > 0) {
int bytesToCopy = BUFFER_SIZE;
if (bytesToCopy > byteCount) {
bytesToCopy = byteCount;
}
bytesToCopy = inputStream.read(byteBuffer, 0, bytesToCopy);
outputStream.write(byteBuffer, 0, bytesToCopy);
byteCount -= bytesToCopy;
// 64KB has better throughput but is *suspected* to increase the probability
// of AssetInputStream#read() returns -1 early. Use general page size 4KB.
byte[] byteBuffer = new byte[BUFFER_SIZE_NORMAL];
int readCount;
while ((readCount = inputStream.read(byteBuffer)) != -1) {
outputStream.write(byteBuffer, 0, readCount);
readTotal += readCount;
}
// We need the file to be available immediately.
// The flush method inherited from OutputStream MAY do nothing, but sync does!
outputStream.flush();
outputStream.getFD().sync();
}
hasSucceeded = true;
hasSucceeded = (byteCount == readTotal);
}
}
}
Expand All @@ -995,8 +1015,14 @@ public boolean copyFile(java.io.File sourceFile, java.io.File destinationFile) {
try { outputStream.close(); }
catch (Exception ex) { }
}
if (!hasSucceeded) {
destinationFile.delete();
if (tmpFile != null) {
if (hasSucceeded) {
hasSucceeded = false;
// Success if and only if it is successfully copied and renamed.
try { hasSucceeded = tmpFile.renameTo(destinationFile); }
catch (Exception ex) { }
}
if (!hasSucceeded) tmpFile.delete();
}
}
return hasSucceeded;
Expand Down

0 comments on commit aa4140d

Please sign in to comment.