attach binary to android app - android

i am breaking my brain trying to attach an arm pre-compiled binary to my private android app.
if you don't mind, i tell you about my app. it just needs to modify iptables rules because of my gprs communication with my robot. it is a remote control for android, and i get better results if i deny all traffic instead my robot's one.
so i compiled an iptables with my cyanogenmod's version 11 iptables, but with -save -restore support, since i want to restore the rules after finishing the control of my robot..
the thing is that i've been searching in google for a lot of while, and i just found droidwall which seems to only create a 'raw' directory into the 'res' top dir, and once installed, i can see on adb shell the folder 'app_bin' inside /data/data's path.
but when i do install my app, with those dirs createds i can not see even the binary in some strange path... really, is this a very rare case? I don't find any documentation on the network...
thanks a lot,
hope you find it helpful.
abel.
EDIT (possible sollution)
I've downloaded the code from android_firewall project, where it seems to be copying from the apk resource, to the bin directory:
./src/com/jtschohl/androidfirewall/Api.java: final String app_iptables = dir + "/iptables_armv5";
./src/com/jtschohl/androidfirewall/Api.java: // Check iptables_armv5
./src/com/jtschohl/androidfirewall/Api.java: File file = new File(ctx.getDir("bin", 0), "iptables_armv5");
./src/com/jtschohl/androidfirewall/Api.java: copyRawFile(ctx, R.raw.iptables_armv5, file, "755");
I am going to try. Keep on news...

Yes, this is the sollution. The folder name "app_%{TYPE}" is the one returned by the calling of the function getDir(%{TYPE}, MODE_PRIVATE);
So the following code, does the desired functionality:
private static void copyRawFile(Context ctx, int resid, File file, String mode) throws IOException, InterruptedException {
final String abspath = file.getAbsolutePath();
// Write the iptables binary
final FileOutputStream out = new FileOutputStream(file);
final InputStream is = ctx.getResources().openRawResource(resid);
byte buf[] = new byte[1024];
int len;
while ((len = is.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
is.close();
// Change the permissions
Runtime.getRuntime().exec("chmod " + mode + " " + abspath).waitFor();
}
private boolean assertBinaries(Context ctx, boolean showErrors) {
try {
File file = new File(ctx.getDir("bin", MODE_PRIVATE), "xtables_multi");
if (!file.exists()) {
copyRawFile(ctx, R.raw.xtables_multi, file, "755");
}
file = new File(ctx.getDir("bin", MODE_PRIVATE), "iptables_new.sh");
if (!file.exists()) {
copyRawFile(ctx, R.raw.iptables_new, file, "755");
}
} catch(Exception e) {
if (showErrors) {
alert(ctx, R.string.error_assertbinaries + " " + e);
}
return false;
}
return true;
}
public static void alert(Context ctx, CharSequence msg) {
if (ctx != null) {
Toast.makeText(ctx, msg, Toast.LENGTH_SHORT).show();
}
}
Hope that helps,
cheers; Abel.

Related

Android Storage Access Framework - ParcelFileDescriptor - creates 0B file when writing file

Stackoverflow
And thank you so much for reading this question.
I am currently trying to fetch an certain entire directory from my Linux server to
My android phone via sftp.
So far, My code worked fine.
However as soon as I built my app as Signed APK and installed it, Code below does not work as expected.
It doesn't download file from my Linux server but create 0B size files.
private void recursiveFolderDownload(String src, DocumentFile pickedDir) throws SftpException, InterruptedException {
Vector<ChannelSftp.LsEntry> fileAndFolderList = channelSftp.ls(src);
for (ChannelSftp.LsEntry item : fileAndFolderList) {
if (!item.getAttrs().isDir()) {
DocumentFile newFile = pickedDir.findFile(item.getFilename());
if(newFile==null){
MainActivity.changeLoadingMessage("Fetching "+item.getFilename());
restoreStatus = "Fetching "+item.getFilename();
newFile = pickedDir.createFile("",item.getFilename());
restoringFiles.add(getPathFromUri(newFile.getUri()));
write(src + "/" + item.getFilename(),newFile.getUri());
}
else{
MainActivity.changeLoadingMessage("Skipping "+item.getFilename());
restoreStatus = "Skipping "+item.getFilename();
}
} else if (!(".".equals(item.getFilename()) || "..".equals(item.getFilename()))) {
DocumentFile newDir = pickedDir.findFile(item.getFilename());
if(newDir==null){
newDir = pickedDir.createDirectory(item.getFilename());
}
recursiveFolderDownload(src + "/" + item.getFilename(), newDir);
}
}
}
private void write(String src, Uri uri) throws InterruptedException {
try {
ParcelFileDescriptor descriptor = context.getContentResolver().openFileDescriptor(uri,"w");
if(descriptor!=null) {
FileOutputStream fos=new FileOutputStream(descriptor.getFileDescriptor());
channelSftp.get(src,fos);
fos.close();
}
} catch (IOException | SftpException e) {
e.printStackTrace();
}
}
Of course I implemented Storage Access Framework by using activity with Intent.ACTION_OPEN_DOCUMENT_TREE
It's strange that this code works as non-release APK but not as release APK.
Anyway. Thank you so much for reading this question.
Hope I could find answer.

Xamarin Android Sqlite Db browser

I have my first smartphone since one week and try make a App with Xamarin.
I use SQLite with EntityFrameworkCore to store data.
It is work fine, but to debug easier I want use a SQLite browser.
The database file path is 'data/data/{AppName}/Database.db'.
I debug from a physic device by USB, but when I explore the device with Windows Explorer I cannot find the SQLite DB file. The 'data/data' folder is not available. Then I can not use a SQLite browser to see the data.
In this post, the author use a Android emulator and can see 'data/data' folder :
https://blog.xamarin.com/building-android-apps-with-entity-framework/
But I prefer use a real device.
Have you a solution?
A solution from the MikeT, in development store the db file in available folder like this :
public static string DatabasePath
{
get
{
var dbFolder = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
var fileName = "database.db";
var dbFullPath = Path.Combine(dbFolder, fileName);
return dbFullPath;
}
}
In production, copy the db file to a available folder.
One a real device you would, I believe, need to root the device to directly access the data.
However, what you could do is to copy the database file elsewhere e.g. to external storage. In following is the core process that I use:-
try {
FileInputStream fis = new FileInputStream(dbfile);
OutputStream backup = new FileOutputStream(backupfilename);
//byte[] buffer = new byte[32768];
int length;
while((length = fis.read(buffer)) > 0) {
backup.write(buffer, 0, length);
}
backup.flush();
backup.close();
fis.close();
catch (IOException e) {
e.printStackTrace();
confirmaction = false;
}
I use the following to get the pathname for backupfilename:-
File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),subdirectory);
this.directory = dir.getPath();
I then add the actual filename (which is user input).
Note! I do checks to determine that EXTERNAL storage is mounted etc.
To get the database path i use:-
String dbfilename = this.getDatabasePath(
DBConstants.DATABASE_NAME).getPath();
dbfile = new File(dbfilename);
This is of course Java, but I'd assume that it could be converted/adapted to suit. The crux of the answer is to get the database file into a place from which you can access it.
Call the ExtractDb method from your activity
public void ExtractDB()
{
var szSqliteFilename = "databasename.db3";
var szSourcePath = new FileManager().GetLocalFilePath(szSqliteFilename);
var szDatabaseBackupPath = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/databasename_Backup.db3";
if (File.Exists(szSourcePath))
{
File.Copy(szSourcePath, szDatabaseBackupPath, true);
Toast.MakeText(this, "Copied", ToastLength.Short).Show();
}
}
Get path to the android device storage as shown below
public class FileManager
{
public string GetLocalFilePath(string filename)
{
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return Path.Combine(path, filename);
}
}
you need to add the android.permission.WRITE_EXTERNAL_STORAGE permission in your manifest file.

Why the txt file did not create in Android?

I am developing in Android , I found a sample code and it read and write the data to the txt file like the following code:
The following function is for writing data to text file:
private static final String MESH_DATA_FILE_NAME = "TEST.txt";
public void save(Activity activity) {
try {
int i;
Context context = activity;
FileOutputStream fos = activity.openFileOutput(MESH_DATA_FILE_NAME, context.MODE_PRIVATE);
String str;
for (i = 0; i < 10; i++) {
str += "##" + i;
}
fos.write(str.getBytes());
fos.write('\n');
fos.close();
} catch (Exception e) {
Log.e(TAG, "saveMeshInfo exception: " + e);
}
}
The following code for reading data from text file:
public void read(Activity activity) {
try {
FileInputStream fin = activity.openFileInput(MESH_DATA_FILE_NAME);
BufferedReader br = new BufferedReader(new InputStreamReader(fin));
Log.i(TAG, "From file [" + MESH_DATA_FILE_NAME + "]...");
// Read the information
String text = br.readLine();
String[] strs = text.split("##", 4 + FloodMesh.IV_LEN + FloodMesh.KEY_LEN);
fin.close();
} catch (Exception e) {
}
}
It can see the data from the log when it call read function , so the TEST.txt should be exists.
But I didn't found the TEST.txt via file manager app on my android phone.
Why I didn't found the TEST.txt file on my android phone ?
If the TEST.txt not exists , why the read function can read the data ?
How to find the TEST.txt file ?
You've created file in you app directory (/data/data/your.package) and you don't have access there via file manager. The file exists that is why you can read it via method but you won't see it. Test your code on emulator - than you will be able to see the file
If you want to test it better and you don't want to use emulator you can save file on sdcard, you have access there via file manager and you will be able to see it
your file will be in /data/data/<your package name>/files/ - either you have root and an explorer to see this or you use the run-as command on adb to explore the file
With the right permission you can also write the file to sd-card - then accessing it is easier - depends on your needs
You didn't found the TEST.txt because it's in private mode, you need to write MODE_APPEND,You should check http://developer.android.com/reference/android/content/Context.html.
activity.openFileOutput() This method opens a private file associated with this Context's application package for writing. see doc

android copy /dev/log/* to SD card failer

GUYS
I'm new to android and this is my first post in StackOverflow.English as my second language,I'm not that good at it.I just looked for some answers here before,Now I think it's time for me to get involved in it.
There have been a problem occured when I try to copy the system log which located in /dev/log/* to my SD card.After some search on the answers here,I came across Copy file (image) from CacheDir to SD Card.So I had my code below:
private final String srcLocation = "/dev/log/radio";
private final String desLocation = "/mnt/sdcard/radio";
FileInputStream src;
FileOutputStream dst;
FileChannel mFCsrc;
FileChannel mFCdst;
public boolean copyFile(String sourceLocation, String destLocation) throws IOException {
try {
File sd = Environment.getExternalStorageDirectory();
if(sd.canWrite()){
File source=new File(sourceLocation);
File dest=new File(destLocation);
if(!dest.exists()){
dest.createNewFile();
}
if(source.exists()){
src = new FileInputStream(source);
dst = new FileOutputStream(dest);
mFCsrc = src.getChannel();
mFCdst = dst.getChannel();
mFCsrc.transferTo(0, mFCsrc.size(), mFCdst);
}
}
return true;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
if (mFCsrc != null) {
mFCsrc.close();
}
if (mFCdst != null) {
mFCdst.close();
}
}
}
I do have the file in my SD card which I can see it from my DDMS window,but it's size is 0.So,anyone gets a clue? Thanks in advance.(I try to give you a picture of my DDMS window,but since my reputation is not enough,I cann't use a picture.I'm sorry about that!!)
You should debug. Step trough your code with the debugger and check what is happening.
Random thing that might be happening, but we have no way of knowing for sure: If "source" doesn't exist, you will create dest, but because source.exists() will return false,you don't do anything after that. You'll end up with the current behaviour, a newly created file without contents.

Copy a text file on SD card at the time of application installation?

I am working on an android game. I want to copy a text file to external SD card when the user installs the game for the first time. The text file is important for properly running the game.
How can I do that? Where should i place the text file in eclipse source project so that when i build the apk file, my text file also gets bundled in it and when a use installs application from that apk file the text file gets copied to "SDcard\data" folder.?
What code should i write and where, so that it gets executed only once at installation time.
Thanks in advance
This is the methods I use to copy a file to the sd card when the app is first installed:
public class StartUp extends Activity {
/**
* -- Called when the activity is first created.
* ==============================================================
**/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirstRun();
}
private void FirstRun() {
SharedPreferences settings = this.getSharedPreferences("YourAppName", 0);
boolean firstrun = settings.getBoolean("firstrun", true);
if (firstrun) { // Checks to see if we've ran the application b4
SharedPreferences.Editor e = settings.edit();
e.putBoolean("firstrun", false);
e.commit();
// If not, run these methods:
SetDirectory();
Intent home = new Intent(StartUp.this, MainActivity.class);
startActivity(home);
} else { // Otherwise start the application here:
Intent home = new Intent(StartUp.this, MainActivity.class);
startActivity(home);
}
}
/**
* -- Check to see if the sdCard is mounted and create a directory w/in it
* ========================================================================
**/
private void SetDirectory() {
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
extStorageDirectory = Environment.getExternalStorageDirectory().toString();
File txtDirectory = new File(extStorageDirectory + "/yourAppName/txt/");
// Create
// a
// File
// object
// for
// the
// parent
// directory
txtDirectory.mkdirs();// Have the object build the directory
// structure, if needed.
CopyAssets(); // Then run the method to copy the file.
} else if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED_READ_ONLY)) {
AlertsAndDialogs.sdCardMissing(this);//Or use your own method ie: Toast
}
}
/**
* -- Copy the file from the assets folder to the sdCard
* ===========================================================
**/
private void CopyAssets() {
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("");
} catch (IOException e) {
Log.e("tag", e.getMessage());
}
for (int i = 0; i < files.length; i++) {
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(files[i]);
out = new FileOutputStream(extStorageDirectory + "/yourAppName/txt/" + files[i]);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
For this target the best way is make SharedPreferences or your file must be added in "assets" directory in android project.
as per link
There is the ACTION_PACKAGE_ADDED Broadcast Intent, but the application being installed doesn't receive this.
So it looks using SharedPreferences is the easiest way...
SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(this);
boolean firstRun = p.getBoolean(PREFERENCE_FIRST_RUN, true);
p.edit().putBoolean(PREFERENCE_FIRST_RUN, false).commit();
Put the file in the assets folder. Then, using whatever logic you come up with, when your app launches determine if it is the first run of the app.
If it is you can use getAssets() from an Activity to access the asset file and just copy it to wherever necessary.
Since the file on the sdcard is something that could be accidentally deleted by the user, you should probably check directly for its presence (and possibly verify contents) rather than trying to use something independent such as a shared preference to tell if this is the first run of the activity.
For purposes of potential app upgrades, you should probably put a version number in the file, and check that.
If the file is something you want to let power users manually edit (to change expert options) then you may have a little bit of a challenging situation to handle on upgrade.

Categories

Resources