illegalStateException in onLoadFinishe - java

java.lang.IllegalStateException: Can not perform this action inside of
onLoadFinished
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1886)
at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1905)
at android.app.BackStackRecord.commitInternal(BackStackRecord.java:688)
at android.app.BackStackRecord.commit(BackStackRecord.java:646)
at android.app.DialogFragment.dismissInternal(DialogFragment.java:312)
at android.app.DialogFragment.dismiss(DialogFragment.java:278)
Why I am getting this crash in play store console for some of my users. This is not device or OS specific.
I am not doing any UI related transaction in onLoadFinished. I am executing ABCAsyncTask, and in onPostExecute of it, i am calling pausehandler to execute the UI.
Additionally, As I am using two cursors, so onLoadFinished in called twice here.
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
if (cursor == null) {
Log.e(LOG_TAG, "cursor is null");
return;
}
(new ABCAsyncTask(this, cursorLoader, cursor)).execute();
}
ABCAsyncTask ->
onPostExecute() {
LoadItemPauseHandlerObject loadItemPauseHandlerObject = new LoadItemPauseHandlerObject ();
Message responseMessage = new Message();
responseMessage.what = 1; // some int
responseMessage.obj = loadItemPauseHandlerObject;
pauseHandler.sendMessage(responseMessage);
}
In android OS source code:
void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
String lastBecause = null;
if (mHost != null) {
lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
}
try {
if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": "
+ loader.dataToString(data));
mCallbacks.onLoadFinished(loader, data);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
since finally {} block will always be executed synchronously after try {} block in the main thread, and in onLoadFinished() i am not doing any fragment transaction directly, so, mNoTransactionsBecause should reset to lastBecause then why this crash is coming for some of my users?
I am using :
android.app.LoaderManager android.app.Activity android.app.Fragment

Try adding check
isAdded()
in your handleMessage() method of your handler possibly it would be in your Fragment.
Let me know if you have further doubt

Related

Semaphore does not invoke release()

I have implemented a thread in an Android app that is invoked every minute, the invocation of the process occur through an Alarm Manager.
#Override
public void onReceive(Context context, Intent intent) {
try {
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock;
if (powerManager != null) {
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Send-data");
wakeLock.acquire(10 * 60 * 1000L);
new Thread(new SendPolicyData(context)).start();
wakeLock.release();
}
} catch (Exception e) {
wil.WriteFile("1)AlarmSendData - Exception: " + e.toString());
}
}
The code contained in the thread extract a set of data from a database that must be sent through posts to a server, the access to resources is controlled via a semaphore.
#SuppressWarnings("ResultOfMethodCallIgnored")
public class SendPolicyData implements Runnable {
private static final WriteInLogFile wil = new WriteInLogFile();
private final Context ctx;
public SendPolicyData(Context ctx) {
this.ctx = ctx;
}
public void run() {
try {
SemaphoreDTS.getInstance().goIn();
Authentication singleCall = new Authentication();
Utilities utilities = new Utilities(ctx);
DbGest dbGest = DbGest.getInstance(ctx);
if (utilities.checkConnection()) {
int lastProcessedID = -1;
int attempts = 0;
Cursor cursor = dbGest.freeQuery("SELECT id, label, value, priority FROM " + TABLE_DATATOSEND + " ORDER BY priority,dateIns");
if (cursor != null) {
cursor.moveToFirst();
if (cursor.getCount() > 0) {
do {
int toProcessID = cursor.getInt(cursor.getColumnIndex("id"));
String value = cursor.getString(cursor.getColumnIndex("value"));
String labelString = cursor.getString(cursor.getColumnIndex("label"));
if (lastProcessedID == toProcessID) {
if (attempts <= 5) {
attempts++;
Thread.sleep(3000);
} else {
attempts = 0;
dbGest.changeDTSRecordPriority(toProcessID);
}
}
switch (labelString) {
case "photo":
//DO STUFF
break;
lastProcessedID = toProcessID;
} while (cursor.moveToNext());
}
cursor.close();
}
}
} catch (Exception e) {
SemaphoreDTS.getInstance().goOut();
wil.WriteFile("7)SendPolicyData - Exception: " + e.toString());
} finally {
SemaphoreDTS.getInstance().goOut();
}
SemaphoreDTS.getInstance().goOut();
}
}
This is the source code of the semaphore that I use to manage the access to the resources.
public class SemaphoreDTS {
private static SemaphoreDTS instance;
private final Semaphore semaphore;
private final WriteInLogFile wil = new WriteInLogFile();
private SemaphoreDTS() {
this.semaphore = new Semaphore(1, true);
}
public static SemaphoreDTS getInstance() {
if (instance == null) {
instance = new SemaphoreDTS();
}
return instance;
}
public synchronized void goIn() {
try {
semaphore.acquire();
} catch (Exception e) {
wil.WriteFile("1)SemaphoreDTS - Exception: " + e.toString());
}
}
public synchronized void goOut() {
try {
semaphore.release();
} catch (Exception e) {
wil.WriteFile("2)SemaphoreDTS - Exception: " + e.toString());
}
}
}
During the tests that I did, it often happens that the semaphore remains blocked, for some reason the necessary release is not invoked in order to be able to perform new acquire.
I think I have written the code correctly and I don't understand where I am wrong.
In this code's block:
catch (Exception e) {
SemaphoreDTS.getInstance().goOut();
wil.WriteFile("7)SendPolicyData - Exception: " + e.toString());
} finally {
SemaphoreDTS.getInstance().goOut();
}
SemaphoreDTS.getInstance().goOut();
You always have two calls .goOut(), because finally block always will invoke.
When you call .release() (in your method .goOut()) semaphore gets availible permit, i.e instead 1 permit your semaphore gets 2 permits. I think problem starts here. Try to delete calls `.goOut() method everywhere but not in finally()

Imposible to force kill freezed thread in java android

I have one very unusual case when calling an Android hidden API over reflection freezes the calling thread eternally. I cannot debug the underlying code as it is a code from Android itself normally not visible. I tried running the code in an asynctask, in a normal thread but nor asynctask.cancel nor thread.interrupt kills the thread, the thread stays visible, I can see it while debugging. Is it really not possible to run a code encapsulated and kill it completely eventually?
This problems occurs only on Android O and only on some devices, that's why I need to test-run it to see if it works on the current device and be able to activate a feature according to that. The code below, I don't really see a solution for this:
Thread endCallThread;
Runnable myRunnable;
private void checkFeatureSupport(final Context context) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
myRunnable = new Runnable() {
#Override
public void run() {
doInBackgroundWrapper();
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
//handleResult();
}
});
}
}
};
endCallThread = new Thread(myRunnable, "endCallThread");
endCallThread.start();
new CountDownTimer(3000, 3000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Log.e("TESTAUTOMATION", "endCall did not finished in 3 seconds");
// stop async task if not in progress
if (endCallThread.isAlive()) {
try {
endCallThread.interrupt();
endCallThread = null;
myRunnable = null;
System.gc();
Log.e("TESTAUTOMATION", "endCallThread interrupted");
} catch (Exception ex) {
Log.e("TESTAUTOMATION", "endCallThread interrupted exception");
}
//handleResult();
}
}
}.start();
} else {
mEndCallSupported = true;
}
}
}
private void doInBackgroundWrapper() {
try {
if (getContext() == null) {
return;
}
final TelephonyManager telMan = (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
if (telMan == null) {
return;
}
final Class<?> classTemp = Class.forName(telMan.getClass().getName());
final Method methodTemp = classTemp.getDeclaredMethod("getITelephony");
methodTemp.setAccessible(true);
ITelephony telephonyService = (ITelephony) methodTemp.invoke(telMan);
// If this call does not return a security exception we say the call principally works.
Log.d("TESTAUTOMATION", "endCall before");
// This call endCall may freeze depending on device, mostly seen on Nexus 5x with Android 8&8.1
telephonyService.endCall();
Log.d("TESTAUTOMATION", "endCall after");
mSupported = true;
} catch (Exception ex) {
ex.printStackTrace();
mSupported = false;
}
}
To reproduce this the device should better no have a SIM inserted.
Thread.interrupt() in a common case does not stop a thread, it just marks specific boolean field (isInterrupted) as true. If a developer wants to stop thread's work at some point (after calling Thread.interrupt()) he can rely on this boolean filed Thread.isInterrupted() when he is implementing some work in a separate thread.
So I guess there is no such checking in the reflected hidden method what you are trying to call.
To stop your thread you can try deprecated Thread.stop() but it is a really bad practice.

NullPointerException in creating ProvisioningJob for headless update of eclipse rcp application

I am implementing headless force update of the eclipse application. I have used the P2Util class from https://help.eclipse.org/neon/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Fguide%2Fp2_startup.htm but my code is returning null pointer exception at ProvisioningJob job = operation.getProvisioningJob(null); the job object is coming null. Does anyone know the possible reason for this null object.
public class P2Util {
// XXX Check for updates to this application and return a status.
static IStatus checkForUpdates(IProvisioningAgent agent, IProgressMonitor monitor) throws OperationCanceledException {
ProvisioningSession session = new ProvisioningSession(agent);
// the default update operation looks for updates to the currently
// running profile, using the default profile root marker. To change
// which installable units are being updated, use the more detailed
// constructors.
UpdateOperation operation = new UpdateOperation(session);
SubMonitor sub = SubMonitor.convert(monitor,
"Checking for application updates...", 200);
IStatus status = operation.resolveModal(sub.newChild(100));
if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
return status;
}
if (status.getSeverity() == IStatus.CANCEL)
throw new OperationCanceledException();
if (status.getSeverity() != IStatus.ERROR) {
// More complex status handling might include showing the user what updates
// are available if there are multiples, differentiating patches vs. updates, etc.
// In this example, we simply update as suggested by the operation.
ProvisioningJob job = operation.getProvisioningJob(null);
status = job.runModal(sub.newChild(100));//null pointer here
if (status.getSeverity() == IStatus.CANCEL)
throw new OperationCanceledException();
}
return status;
}
}
I am calling this method as follows.
private Integer checkUpdate(final String updateServerURL, final IProvisioningAgent provisioningAgent, ProgressMonitorSplash monitor) {
returnValue = IApplication.EXIT_OK;
final IRunnableWithProgress runnable = new IRunnableWithProgress() {
#Override
public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
P2Util.addRepository(provisioningAgent, updateServerURL);
final IStatus updateStatus = P2Util.checkForUpdates(provisioningAgent, monitor);
if (updateStatus.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) {
logger.debug("No Updates");
} else if (updateStatus.getSeverity() != IStatus.ERROR) {
logger.debug("Updates applied, attempting restart");
returnValue = IApplication.EXIT_RESTART;
} else {
logger.error(updateStatus.getMessage());
}
}
};
try {
monitor.run(true, runnable);
} catch (final InvocationTargetException e) {
e.printStackTrace();
} catch (final InterruptedException e) {
logger.error("interrupted: " + e.getMessage());
}
return returnValue;
}
where I am creating ProvisingAgent using EclipseContext
final IEclipseContext localContext = EclipseContextFactory.getServiceContext(Activator.getContext());
final IProvisioningAgent provisioningAgent = getService(localContext, IProvisioningAgent.class);
String env = System.getProperty("env").toLowerCase();
String repo = System.getProperty("validUrl." + env);
if ( repo == null ){
repo = System.getProperty("validUrl");
}
if ( repo != null ){
ret = checkUpdate(repo, provisioningAgent, sp);
if ( ret == IApplication.EXIT_RESTART ){
logger.info("Update successful, restarting...");
return ret;
}
}
The javadoc on the UpdateOperation#getProvisioningJob(IProgressMonitor) says:
* #return a job that can be used to perform the provisioning operation. This may be <code>null</code>
* if the operation has not been resolved, or if a plan could not be obtained when attempting to
* resolve. If the job is null and the operation has been resolved, then the resolution result
* will explain the problem.

Is it safe to use try with resources in Java - does it check if the closeable is not null and does it catch exceptions while trying to close it

Is it safe to use Java's try with resources in Android- does it check if the closeable is not null and does it catch exceptions thrown by close while trying to close it?
if I convert this:
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} finally {
if (inChannel != null) {
inChannel.close();
}
if (outChannel != null) {
outChannel.close();
}
}
to
try (FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel()) {
inChannel.transferTo(0, inChannel.size(), outChannel);
}
will it check if inChannel and outChannel are not null before trying to call close?
Also, is it safe to use try with resources here:
try {
cursor = context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media.DATA},
MediaStore.Images.Media._ID + " =? ",
new String[]{"" + imageIdInMediaStore},
null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
return cursor.getString(0);
} else {
return "";
}
} catch (Exception e) {
return "";
} finally {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
cursor = null;
}
}
The finally block does an important check for !cursor.isClosed() - will try with resources figure out how to do that, or should I leave this unchanged?
The easiest way to find that out yourself is writing a test class simply telling you about it:
import junit.framework.TestCase;
public class __Test_AutoClosable extends TestCase {
public void testWithNull() throws Exception {
try (TestClosable tc = getNull()) {
assertNull("check existance of closable", tc);
}
}
public void testNonNullWithoutException() throws Exception {
try (TestClosable tc = getNotNull(false)) {
assertNotNull("check existance of closable", tc);
}
}
public void testNonNullWithException() throws Exception {
try (TestClosable tc = getNotNull(true)) {
assertNotNull("check existance of closable", tc);
}
catch(Exception e) {
assertEquals("check message", "Dummy Exception", e.getMessage());
}
}
TestClosable getNull() {
return null;
}
TestClosable getNotNull(boolean throwException) {
return new TestClosable(throwException);
}
static class TestClosable implements AutoCloseable {
private boolean throwException;
TestClosable(boolean throwException) {
this.throwException = throwException;
}
#Override
public void close() throws Exception {
if (throwException) {
throw new Exception("Dummy Exception");
}
}
}
}
This class runs through without errors, so the answers to your questions are:
Yes, null as response is possible, it is checked in the close-phase
Exceptions thrown on close are not catched but must be catched and handled by yourself
If you think about this a bit, that makes complete sense. Not supporting null would draw the whole construct useless, simply ignoring closes, even if they are implicitly done, is a bad, bad thing.
Edit: The testcase above is the result but for a "real" test, e.g. being added to your source base, you should actually check if the close-method in the autoclosable has been called.
Concerning your second question: If there are cases where you don't want the close to happen, a 1:1-change to try-with-resources doesn't work but you can do something like this:
public class CursorClosable implements AutoClosable {
private Cursor cursor;
public CursorClosable(Cursor cursor) {
this.cursor = cursor;
}
public Cursor getCursor() {
return cursor;
}
#Override
public void close() throws Exception {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
}
Your new code would then look like this:
try (Cursor cursorac = new CursorClosable(context.getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media.DATA},
MediaStore.Images.Media._ID + " =? ",
new String[]{"" + imageIdInMediaStore},
null)) {
Cursor cursor = cursorac.getCursor();
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
return cursor.getString(0);
} else {
return "";
}
} catch (Exception e) {
return "";
}
I'm not sure if the check for isClosed is really necessary so maybe you don't need this kind of "hack" for this particular example but it's still valid for other examples where you don't want to close resources.

A class's instance gets destroyed when inner class's method exits?

I am going to use Xposed Bridge API to customize my status bar on my Android phone.
Hooking methods are working pretty well, but there's a problem.
public class WPSModule implements IXposedHookLoadPackage {
final int ICON_SIZE = 100;
FrameLayout FlStatusBar;
...
void HideWidget(FrameLayout FlLayout, String Name)
{
int ViewId = FlLayout.getResources().getIdentifier(Name, "id", "com.android.systemui");
if(ViewId == 0)
{
XposedBridge.log("Failed to find resource " + Name + " on systemui package.");
return;
}
View v = FlLayout.findViewById(ViewId);
if(v == null)
{
XposedBridge.log("v == null with resource " + Name + " on systemui package.");
return;
}
v.setVisibility(View.INVISIBLE);
}
public static TextView TvText = null;
public void handleLoadPackage(final LoadPackageParam LppParam) throws Throwable {
if (!LppParam.packageName.equals("com.android.systemui"))
return;
XposedBridge.log("WPS: SystemUI package found.");
//Hook
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBarView", LppParam.classLoader, "onFinishInflate", new XC_MethodHook() {
#Override
protected void beforeHookedMethod(MethodHookParam MhpParam) throws Throwable {
// this will be called before the clock was updated by the original method
}
#Override
protected void afterHookedMethod(MethodHookParam MhpParam) throws Throwable {
FlStatusBar = (FrameLayout) MhpParam.thisObject;
}
});
....
}
}
And when I try to use FlStatusBar like this:
HideWidget(FlStatusBar, "notification_lights_out");
It doesn't work. On Xposed's log...
07-31 20:22:09.962 E/Xposed (18737): java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.widget.FrameLayout.getResources()' on a null object reference.
Other things which uses FlStatusBar doesn't work too..(ex: FlStatusBar.toString() gives me NullPointerException)

Categories