Can Android Studio local file cache feature help me to restore my accidently deleted file?

Answered

Hi,

I'm developing a small free Android application (Flappy) in Android Studio (which is based on Intellij Idea, right?).

I have accidently removed my keystore file (flappy.jks) where I've kept the certificate to sign the application.

I have unfortunately also removed the project from the Android Studio menu. 

But I found out that the file is still being referenced in the Android Studio cache folder which is (I believe) used to keep the local file changes. The file name (flappy.jks) I found in those three files:

c:\Users\panuska\.AndroidStudio2.3\system\LocalHistory\changes.storageData

c:\Users\panuska\.AndroidStudio2.3\system\caches\names.dat.keystream

c:\Users\panuska\.AndroidStudio2.3\system\index\filenameindex\FilenameIndex.storage.keystream

 

I believe the original content of the removed file is still stored in the cache. If I knew the format of the cache, I would be able to extract the file content, right? Is this cache format described somewhere?

 

Thanks as this would help me a lot (it's not possible to publish an Android application update once the certificate gets lost).

 

Petr Panuska

0
9 comments
Avatar
Permanently deleted user

Hi Serge, thanks for your comment. I'm aware of the local history feature of Idea / Android Studio. The trouble is that I already removed the project from Android Studio; I can't open it (unless I somehow fake the *.iml file). Not sure how to do it...

I really need to work on the binary files in the Studio cache folder.

0

Are you sure the project root directory is removed? If you removed it from AS menu, it doesn't mean that it's removed from disk, try to Open it from the original location.

There is no documentation for that available or an easy way to extract files from history/cache, you can investigate the source code of this subsystem and write your own tool to extract files, if possible.

0

Try creating a new project in a new location, then close AS and move this new project to the location of the old one, open the project from the old location and see if you can use local history, backup IDE cache/history files just in case.

0
Avatar
Permanently deleted user

Also, I know the JKS binary file starts with a magic number (0xfeedfeed). I belive the cache content is somehow encoded (compressed), if I knew how to decompress the data, I would be able to identify the start of the JKS file in it and will be able to eventually extract it all.

Are the data compressed? How?

0
Avatar
Permanently deleted user

Thanks Serge, I'll try the Snappy library to implement my simple decompress tool.

0
Avatar
Permanently deleted user

This is the code that helped me to extract files from Android local files cache. BTW, it was not compressed using Snappy.

 

import com.intellij.mock.MockProjectEx;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.impl.ApplicationImpl;
import com.intellij.openapi.components.ExtensionAreas;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.vfs.newvfs.persistent.FSRecords;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.content.TabbedPaneContentUI;
import com.intellij.ui.content.impl.ContentManagerImpl;

import java.io.*;

public class Tool {

public static void main(String[] args) throws IOException {
System.setProperty("caches_dir", "c:\\zz\\studio-cache");

Extensions.registerAreaClass(ExtensionAreas.IDEA_PROJECT, null);
Extensions.registerAreaClass(ExtensionAreas.IDEA_MODULE, ExtensionAreas.IDEA_PROJECT);

ContentManager manager = new ContentManagerImpl(new TabbedPaneContentUI(), false, new MockProjectEx(new TestDisposable()));
ApplicationManager.setApplication(new ApplicationImpl(false, false, false, false, "test", null), manager);

FSRecords.connect();

int numRecords = FSRecords.getMaxId();
for (int i = 0; i < numRecords; i++) {
CharSequence name = FSRecords.getNameSequence(i);
if (name.toString().endsWith("jks")) {
try {
DataInputStream stream = FSRecords.readContent(i);
int size = stream.available();

byte[] buffer = new byte[size];
stream.readFully(buffer);
stream.close();
OutputStream out = new FileOutputStream("c:\\zz\\temp\\file-" + i + "-"+name);
out.write(buffer);
out.close();
System.out.println(i + ": " + FSRecords.getNameSequence(i));
} catch (Exception e) {
System.out.println(i+": "+FSRecords.getNameSequence(i)+" - cannot be saved");
}

}
}
}
}

 

Also I had to add couple of JARs on class path.

  • C:\Program Files\Android\Android Studio\lib\boot.jar
  • C:\Program Files\Android\Android Studio\lib\bootstrap.jar
  • C:\Program Files\Android\Android Studio\lib\extensions.jar
  • C:\Program Files\Android\Android Studio\lib\idea.jar
  • C:\Program Files\Android\Android Studio\lib\jna-platform.jar
  • C:\Program Files\Android\Android Studio\lib\log4j.jar
  • C:\Program Files\Android\Android Studio\lib\openapi.jar
  • C:\Program Files\Android\Android Studio\lib\picocontainer.jar
  • C:\Program Files\Android\Android Studio\lib\trove4j.jar
  • C:\Program Files\Android\Android Studio\lib\util.jar
  • C:\Program Files\Android\Android Studio\lib\snappy-in-java-0.5.1.jar

 

1

Great job! Thanks for sharing the code, I'm sure it will help others with similar issues.

0

Please sign in to leave a comment.