Android application have read/write permission for /data/anr/traces.txt. But still FileObserver does not seem to work for it.
What else is required for FileObserver to work? It works fine for sdcard file.
Code:
mFileObserver = new FileObserver("/data/anr/traces.txt") { // set up a file observer to
#Override
public void onEvent(int event, String file) {
if(event == FileObserver.CLOSE_WRITE)
{
Log.e("TestApp", "ANR has occured");
}
}
};
mFileObserver.startWatching();
Found solution to it therefore answering my own question as it may help others.
Looks like using complete file path "/data/anr/traces.txt" is not working. But using path to "/data/anr" is working ok.
Still not sure why complete path doesn't work.
Before calling mFileObserver.startWatching(), you should make sure the file exists. Or no events will be notified.
Related
I am following this official tutorial. I am facing a problem for setting disk cache root path. I am using Here Map inside a Fragment. Here is the code i am using.
mapFragment = (AndroidXMapFragment)getChildFragmentManager().findFragmentById(R.id.mapFragment);
String diskCacheRoot = getContext().getExternalFilesDir(null) + File.separator + ".here-maps";
boolean success = com.here.android.mpa.common.MapSettings.setIsolatedDiskCacheRootPath(
diskCacheRoot,
getString(R.string.hereMapServiceIntentName));
if (!success){
Toast.makeText(getContext().getApplicationContext(), "Unable to set isolated disk cache path.", Toast.LENGTH_LONG).show();
}else{
// initialize map
}
For the first time i am getting success true. When i come back this Fragment again success is always false.
From official documentation for setIsolatedDiskCacheRootPath method
Returns:
false if path matches default disk cache path or path is a file or
invalid or is not writable or intentAction matches default service
connection name, otherwise true.
Not sure for which case i am getting false.
If i clear my app from recent and relaunch again then First time i got success true.
Can anyone can explain the scenario why this is happening.
Changing the Files Directory method working now. Using getFilesDir instead of getExternalFilesDir is working for me.
String diskCacheRoot = getContext().getFilesDir().getPath() + File.separator + ".here-maps";
Andrew's suggestion is also working for me.
It occurs for me since 3.13.x too, and worked before 3.13.x.
Please read documentation: https://developer.here.com/documentation/android-premium/api_reference_java/com/here/android/mpa/common/MapSettings.html
It is said:
The method must be called before the init() methods on MapEngine.
You cannot run this method after mapEngine is initialised.
To fix this use the following logic:
if (!MapEngine.isInitialized()) {
MapSettings.setIsolatedDiskCacheRootPath(diskCacheRoot, ISOLATED_MAP_SERVICE_INTENT);
...
}
What about sdk premium 3.14.2 ?
Method setIsolatedDiskCacheRootPath() is deprecated ...
https://www.developer.here.com/documentation/android-premium/api_reference_java/com/here/android/mpa/common/MapSettings.html#setIsolatedDiskCacheRootPath-java.lang.String-java.lang.String-
#Deprecated
#HybridPlus
public static boolean setIsolatedDiskCacheRootPath(String var0, String var1) {
return com.nokia.maps.MapSettings.b(var0, var1);
}
I have an app that contains a lib (for example, "test.so") and I want to redirect the load of that .so to another "test.so" which is modified by me, I tried everthing using Xposed like:
public class xposed implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (lpparam.packageName.equals("package")) {
findAndHookMethod("java.lang.System", lpparam.classLoader, "loadLibrary", String.class, new XC_MethodHook() {
#Override
protected void beforeHookedMethod(MethodHookParam param){
XposedBridge.log("(before) Loaded library: " + param.args[0]);
if (param.args[0].toString().equals("test")){
System.load("/data/data/package/modified_test.so");
}
}
});
}
}
}
The app crashes, I searched on Google and I found this: System.loadlibrary hook crash but when I want to hook into Runtime like rovo said it doesn't do nothing. Someone know any solution?
(Please don't tell me about changing the lib into .apk because if I want that I didn't asking this xD).
Your code can not work because you are hooking the wrong method.
System.loadlibrary expects as parameter the library name without file path, without prepended lib and without file extension. Therefore if you replace the parameter with "/data/data/package/modified_test.so" as shown in your example the library loading will not work.
I assume you may have more luck if you hook the method that is responsible for mapping the library name to the actual library file: System.mapLibraryName(String).
You can see how it is used in Runtime.loadLibrary(String, ClassLoader)
To do so use an afterHookedMethod, check the result value and overwrite the return value with the path to your modified library.
I have an android app. I have a few users who have a recurring problem: When the app shuts down, every file the app saved is gone. Every folder created is gone. Everything is completely wiped back to square one.
I am carefully saving the game data during every transition and game event, so I am very confident that this is not a case of the user crashing out before the data can be written. Somehow, the data that IS being written but then it's just not persisting after the app is removed from memory.
So-- has anyone had this situation and solved it? The only thing I can imagine is that there's some kind of "filesystem.commit" command I need to call after writing the files, but I can't find that documented anywhere.
Please help!
(Edit) I'm using native code to read and write files. The code I use to write a file is this:
bool WriteFile(char *theFilename, char *theDataPtr, int theLen)
{
FILE* aFile=fopen(theFilename,"w+");
if(!aFile) {Alert("unable to create file %s with error %d", theFilename, errno);return false;}
if(aFile) fclose(aFile);
aFile=fopen(theFilename,"w+b");
if(!aFile) {Alert ("unable to open file %s", theFilename);return false;}
if (aFile)
{
fwrite(theDataPtr, 1, theLen,aFile);
fclose(aFile);
return true;
}
return false;
}
Note:No customers are reporting any alert popups, which are just normal Android message boxes. Also note that this code works on almost every other system-- there's just a few customers that get the wiped data, so I was wondering if it's some weird security or some extra step I need to do to be 100% compatible with all systems.
(Edit) One more piece of information... this is the Java code I use to get the storage path for the app... all files that I try to write are put in this folder.
private void SetFilePath()
{
String storagePath = getFilesDir().getAbsolutePath();
// SDCARD
try {
String storageState = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(storageState))
storagePath = getExternalFilesDir(null).getAbsolutePath();
} catch (Exception e) {
Log.v(IDS.LOG,
"No permission to access external storage, missing android.permission.WRITE_EXTERNAL_STORAGE");
}
SetFilePathNative(storagePath); // Tells the native code the path
mStorageDir = storagePath;
}
I want to monitor /proc/net/tcp6 file and to do that efficiently with FileObserver, however for some unknown reason onEvent() callback never called.
observerTcp6 = new FileObserver("/proc/net/tcp6", FileObserver.ALL_EVENTS) {
#Override
public void onEvent(int event, String path) {
Log.i("TAG", "onEvent");
}
};
observerTcp6.startWatching();
With regular File class parsing this files works perfect.
Could anyone help me here? :)
The reason of your failure is that /proc/net/tcp6 is not really a file ;-)
It only looks like a file (ex., you can "open" and "read" it), but actually whole /proc/* entries are an interfaces to various kernel statistics\data, represented as "pseudo-files" only for simplifying access to them.
So, you can not use any other file methods on them, except "open" and "read".
P.S.
Your question is Linux related one, not actually Android.
I'm using the >=4.3 NotificationListenerService to access notifications. On the first start, my app takes the user to the "Access Notifications" system panel, but I'd like to take the user there whenever the checkbox for my app in "Access Notifications" is disabled. I haven't found a isNotificationAccessEnabled()-method anywhere, but I definitely know that it's possible because apps like Krome do this, too.
Edit June 15th, 2016
I'm not sure which version of the support library this was added to, but it looks like this functionality is now built in. Simply use:
NotificationManagerCompat.getEnabledListenerPackages(context); (link to docs)
This returns a Set<String> that you can iterate through to find your package name. Note however that I haven't personally tested this. But it looks like it's probably preferred to use this in place of my old solution below.
Old Solution
This code is working for my app:
ContentResolver contentResolver = context.getContentResolver();
String enabledNotificationListeners = Settings.Secure.getString(contentResolver, "enabled_notification_listeners");
String packageName = context.getPackageName();
// check to see if the enabledNotificationListeners String contains our package name
if (enabledNotificationListeners == null || !enabledNotificationListeners.contains(packageName))
{
// in this situation we know that the user has not granted the app the Notification access permission
throw new Exception();
}
else
{
doSomethingThatRequiresNotificationAccessPermission();
}
Typical values that I've seen for the enabledNotificationsListeners String look like this:
User has given none of their apps Notification access permission
null or ""
User has given one app Notification access permission
"com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"
User has given two apps Notification access permission
"com.scootrnova.android/com.scootrnova.android.ListenerService:com.woodblockwithoutco.remotecontrollerexample/com.woodblockwithoutco.remotecontrollerexample.RemoteControlService"
This implementation is very straightforward and works great :)
P.S. I got the idea to use the hardcoded "enabled_notification_listeners" String from this answer.
Starting with Android 8.1 (SDK 27) you can call isNotificationListenerAccessGranted on the NotificationManager. This is the correct API to use. Older Android versions should use getEnabledListenerPackages as a second best option. Relying on your listener callbacks can give incorrect results. See explanation below.
Im developer of Krome. What have I done to check if service is enabled is add public static variable that changes to true in onBind method and to false in unbind. That is how this service work.
Edit:
public static boolean isNotificationAccessEnabled = false;
#Override
public void onListenerConnected() {
isNotificationAccessEnabled = true;
}
#Override
public void onListenerDisconnected() {
isNotificationAccessEnabled = false;
}
Works well with slightly modified #Damians answer
public class NotifyListener extends NotificationListenerService{
public static boolean listnerConnected = false;
#Override
public IBinder onBind(Intent intent) {
Log.d(name,"onBind Called");
listnerConnected = true;
return super.onBind(intent);
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.e("destroy", "called");
listnerConnected = false;
}
}
Starting with Android 8.1 (SDK 27) you can call isNotificationListenerAccessGranted on the NotificationManager. This is the correct API to use, not the one of the accepted answer. See explanation below.
Like shai tibber also already said the accepted answer is incorrect.
onListenerConnected() and onListenerDisconnect() can get called even when there is no NotificationListener access granted. So relying on this callbacks to set a boolean will give wrong results. And getEnabledListenerPackages(context) will just return all the packages that have an enabled notification listener defined in there AndroidManifest (android:enabled=true). It's NOT directly related to the user access. The documentation states exactly that:
Get the set of packages that have an enabled notification listener component within them.