The Android open source code contains code such as this. Can anyone explain why and under which circumstances it is necessary to do SELinux.restorecon(File)?
// If Encrypted file systems is enabled or disabled, this call will return the
// correct directory.
mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup");
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
}
Can we do it too often?
SELinux restorecon is used to restore the default security contexts on some files/dir.
The thing (which is not obvious) is that we also use it to apply context changes, and/or to ensure that the file contexts are as you expect.
Usually, we define/override default security contexts using semanage-fcontext, and then run restorecon to relabel files according to these new defaults.
Here the code tries to relabel mBaseStateDir but fails to do so. It could be that :
there is no policy supporting the default context associated to that directory (given it's path)
mBaseStateDir is mislabeled (context type is not apllicable)
user/process running that code doesn't have the sufficient permission to relabel the directory (even it just created it).
Related
I am working on an app with Appcelerator.
Appcelerator uses nearly the same kind of require.js like node.js does.
Now I want to implement a feature that logges out the current user and does not leave any trace.
The most simple way would be to restart the app, but Appcelerator and especially Apple does not support this.
So i have to open the login window and clean all the data that leaves a trace to the old user.
The easiest way would be to dereference one of the main nodes in the require chain leaving all the data dereferenced and garbage collected.
I know there is a way (as mentioned here) to do that in node:
/**
* Removes a module from the cache
*/
function purgeCache(moduleName) {
// Traverse the cache looking for the files
// loaded by the specified module name
searchCache(moduleName, function (mod) {
delete require.cache[mod.id];
});
// Remove cached paths to the module.
// Thanks to #bentael for pointing this out.
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if (cacheKey.indexOf(moduleName)>0) {
delete module.constructor._pathCache[cacheKey];
}
});
};
/**
* Traverses the cache to search for all the cached
* files of the specified module name
*/
function searchCache(moduleName, callback) {
// Resolve the module identified by the specified name
var mod = require.resolve(moduleName);
// Check if the module has been resolved and found within
// the cache
if (mod && ((mod = require.cache[mod]) !== undefined)) {
// Recursively go over the results
(function traverse(mod) {
// Go over each of the module's children and
// traverse them
mod.children.forEach(function (child) {
traverse(child);
});
// Call the specified callback providing the
// found cached module
callback(mod);
}(mod));
}
};
So I tried to read out the require-cache in Appcelerator with:console.log(require, "-" ,require.cache); with an output like: <KrollCallback: 0x79f6fe50> - <null>
So now my questions:
Is there a way to reach the require-cache in Appcelerator?
Do you know a way to clean up a big Appcelerator-App?
Since it is possible to wirte native Modules for Appcelerator:
Do you know a way to clean up a big Android App?
Do you know a way to clean up a big iOS App?
Thank you very much
In my application I make use of two build flavours / build variants. After switching to two build flavours, a bug was introduced in my application. I have now discovered the reason for this bug, but I am unable to find a solution.
The situation:
In my MainActivity class, I have a function that checks if a file exists - it is very straightforward;
public boolean fileExists(String filename) {
File file = null;
file = this.getApplicationContext().getFileStreamPath(filename);
return file.exists();
}
Using the debugger, location of the file is reported as: /data/data/foo.bar.appname.buildflavour/files/filename
In another class, I try to write to this same location;
outputStream = getActivity().getApplicationContext().openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write("test");
outputStream.close();
However, when I print the following line in front of the outputStream getActivity().getApplicationContext() - context is reported as; com.foo.bar.appname#14fcdd18. Therefore, I believe that these two classes are trying to save / retrieve a file in different locations. Any ideas on how I can make sure that the application is writing the file in the correct build flavour location? Thank you in advance!
You need to use different application id.
Form official site Configuring Gradle Builds
When using build variants, the build system enables you to uniquely identify different packages for each product flavors and build types.
productFlavors {
pro {
applicationId = "com.example.my.pkg.pro"
}
free {
applicationId = "com.example.my.pkg.free"
}
}
Eventually I was able to find the answer to my question. Initially I was calling a function in MainActivity onCreate, but this function was no longer being called because the buildFlavors redirected directly to one of my application fragments.
To anyone coming here with a similar problem: verify that your Flavors call the necessary functions and classes.
I am stuck writing some code that uses reflection that calls IConnectivityManager.startLegacyVpn
The error I get is java.lang.SecurityException: Unauthorized Caller
Looking through the android source I see this is the code hanging me up:
if (Binder.getCallingUid() != Process.SYSTEM_UID) { raise the above exception }
My question is if I root my AVD and install my app in system/app will this be sufficient to get around this error?
If so, any tips on how to do this (every time I try to move my apk to the system/app folder it says the app is not installed when I click on the app icon.
Thanks!
I have the same problem, following android 4.01 open source, i see somethings like this:
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Only system user can call this method.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
}
Or,
// Only system user can revoke a package.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
Or,
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
if (Binder.getCallingUid() != app.uid) {
throw new SecurityException("Unauthorized Caller");
}
jniProtect(socket.getFd(), interfaze);
}
However, these block of code above is belongs to com.android.server.connectivity.Vpn
(class Vpn), which is not defined in interface IConnectivityManager.
I also find in startLegacyVpnInfo() function but i can't see anything involve exception
"Unauthorized Caller", so i wonder why startLegacyVpnInfo() function throws this exception?
Any solutions for this?
I am trying to make the same calls. So far I can confirm that rooting the device and copying the apk to /system/app does not work, it does not start under the system uid.
Also, this does not work:
Field uidField = Process.class.getDeclaredField("SYSTEM_UID");
uidField.setAccessible(true);
uidField.set(null, Process.myUid());
Those calls succeed, but they don't seem to affect the SYSTEM_UID field, the field is probably optimized out at compile time.
If you include android: sharedUserId="android.uid.system" into your manifest tag (not just the manifest), this should then run the application as system. This should now let you run the code.
As for pushing to /system/app, you need to run adb root followed by adb remount. This will now let you push to /system/app.
Which one is faster way to load mobile web pages and non mobile web pages in Android webview; loading cache or not loading that at all?
And what is recommend style to load that?
Right now when I don't load cache at all non mobile sites are much more slower to load than when I load them in native browser.
Don't use these:
viewer.getSettings().setAppCacheMaxSize(1024*1024*8);
viewer.getSettings().setAppCachePath("/data/data/com.your.package.appname/cache");
viewer.getSettings().setAppCacheEnabled(true);
These have nothing to do with the default webview internal cache. Appcache is an entirely different feature mean to make you able to run the website w/o an internet connection. It does not work that great and probably you do not want to use it.
With setting this: viewer.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT) is enough.
Of course, cached approach should be faster. That's the exact reason caching is there in the first place.
But you should be fine unless you specifically disable caching for webview. If you don't - it will use cache by default.
/*
public abstract void setAppCacheEnabled (boolean flag)
Sets whether the Application Caches API should be enabled. The default is false.
Note that in order for the Application Caches API to be enabled, a valid database
path must also be supplied to setAppCachePath(String).
Parameters
flag : true if the WebView should enable Application Caches
*/
// Enable the caching for web view
mWebView.getSettings().setAppCacheEnabled(true);
/*
public abstract void setAppCachePath (String appCachePath)
Sets the path to the Application Caches files. In order for the Application Caches
API to be enabled, this method must be called with a path to which the application
can write. This method should only be called once: repeated calls are ignored.
Parameters
appCachePath : a String path to the directory containing Application Caches files.
*/
/*
public abstract File getCacheDir ()
Returns the absolute path to the application specific cache directory on the
filesystem. These files will be ones that get deleted first when the device runs
low on storage. There is no guarantee when these files will be deleted.
Note: you should not rely on the system deleting these files for you; you should
always have a reasonable maximum, such as 1 MB, for the amount of space you consume
with cache files, and prune those files when exceeding that space.
The returned path may change over time if the calling app is moved to an adopted
storage device, so only relative paths should be persisted.
Apps require no extra permissions to read or write to the returned path,
since this path lives in their private storage.
Returns
The path of the directory holding application cache files.
*/
/*
public String getPath ()
Returns the path of this file.
*/
// Specify the app cache path
mWebView.getSettings().setAppCachePath(mContext.getCacheDir().getPath());
/*
public abstract void setCacheMode (int mode)
Overrides the way the cache is used. The way the cache is used is based on the
navigation type. For a normal page load, the cache is checked and content is
re-validated as needed. When navigating back, content is not re-validated, instead
the content is just retrieved from the cache. This method allows the client to
override this behavior by specifying one of
LOAD_DEFAULT,
LOAD_CACHE_ELSE_NETWORK,
LOAD_NO_CACHE or
LOAD_CACHE_ONLY.
The default value is LOAD_DEFAULT.
Parameters
mode : the mode to use
*/
/*
public static final int LOAD_DEFAULT
Default cache usage mode. If the navigation type doesn't impose any specific
behavior, use cached resources when they are available and not expired, otherwise
load resources from the network. Use with setCacheMode(int).
Constant Value: -1 (0xffffffff)
*/
/*
public static final int LOAD_CACHE_ELSE_NETWORK
Use cached resources when they are available, even if they have expired. Otherwise
load resources from the network. Use with setCacheMode(int).
Constant Value: 1 (0x00000001)
*/
/*
public static final int LOAD_NO_CACHE
Don't use the cache, load from the network. Use with setCacheMode(int).
Constant Value: 2 (0x00000002)
*/
/*
public static final int LOAD_CACHE_ONLY
Don't use the network, load from the cache. Use with setCacheMode(int).
Constant Value: 3 (0x00000003)
*/
// Set the cache mode
mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
I'm dealing with a random problem which related to camera usage. Before I call camera intent - I generate UUID to store file with this name. I store this UUID in private variable like so:
private String requestedFileName;
When camera done - I'm processing this file, looks something like this:
public void onPictureTaken(int index)
{
//First of all - remember picture in database for reference.
FileData.InsertFile(mContext, UUID.fromString(requestedFileName));
//Reduce taken picture if needed, otherwise let it be original.
if (Preferences.getImageSize(mContext) > 0)
{
Imaging.scaleImageFile(mContext, requestedFileName, Preferences.getImageSize(mContext));
}
I see users report issue exception that boils down to requestedFileName == null when onPictureTaken called
Caused by: java.lang.NullPointerException
at java.util.UUID.fromString(UUID.java:210)
at com.idatt.views.FourImagesView.onPictureTaken(FourImagesView.java:151)
at com.idatt.views.TrailerUnitView.onPictureTaken(TrailerUnitView.java:233)
Everything works good on my phone (Nexus S) and in emulator. But users report this exception and I'm not sure why this is happening..
I've seen this happen on the Nexus phones, and some others. If you use DDMS to watch what is going on, I bet you'll see that your process is actually being terminated and then restarted. Thus your local state is being lost. You need to persist it, since Android can basically kill your process and restart it whenever it wants if you switch to a new task (and most of the camera capture intents set the NEWTASK flag).
If your class is an Activity you can use onSaveInstanceState() to store your filename, then read it back out of the Bundle you get in onCreate().
If you are not an Activity you can use the SharedPreferences store as a temporary place to save the filename:
private static void saveTempFileName(Context context, String filename) {
SharedPreferences settings = context.getSharedPreferences("whatever", 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("com.yourstuff.whatever", filename);
editor.commit();
}
As #jeffamaphone noted you are probably having issues with app configuration changes. Application configuration change happens when something happens that affects the runtime environment of your app. Most notably this are: orientation change or keyboard hide/show.
Try this: start your app, invoke the Camera app (via your app action), change orientation, return to your app (via appropriate action). Does this sequence produce the error? Then you have issues with configuration change - when orientation changes usually (depending on your app settings) Android system restarts (kills and creates new instance) your Activity, which probably creates all new Views (without UUID set).
See handling configuration changes.