Skip to content

Commit f43804a

Browse files
Merge pull request #38 from nextcloud/fix-api-init-crash
make requests wait for api to initialize properly
2 parents 19d4c52 + 55d1681 commit f43804a

File tree

3 files changed

+73
-18
lines changed

3 files changed

+73
-18
lines changed

src/main/java/com/nextcloud/android/sso/api/NextcloudAPI.java

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.content.ServiceConnection;
2626
import android.os.IBinder;
2727
import android.os.Looper;
28+
import android.os.NetworkOnMainThreadException;
2829
import android.os.ParcelFileDescriptor;
2930
import android.os.RemoteException;
3031
import android.util.Log;
@@ -34,6 +35,7 @@
3435
import com.nextcloud.android.sso.aidl.IThreadListener;
3536
import com.nextcloud.android.sso.aidl.NextcloudRequest;
3637
import com.nextcloud.android.sso.aidl.ParcelFileDescriptorUtil;
38+
import com.nextcloud.android.sso.exceptions.NextcloudApiNotRespondingException;
3739
import com.nextcloud.android.sso.helper.ExponentialBackoff;
3840
import com.nextcloud.android.sso.model.SingleSignOnAccount;
3941

@@ -49,6 +51,7 @@
4951
import java.io.ObjectOutputStream;
5052
import java.io.Reader;
5153
import java.lang.reflect.Type;
54+
import java.util.concurrent.atomic.AtomicBoolean;
5255

5356
import io.reactivex.Observable;
5457
import io.reactivex.annotations.NonNull;
@@ -57,9 +60,20 @@
5760

5861
public class NextcloudAPI {
5962

63+
private static final String TAG = NextcloudAPI.class.getCanonicalName();
64+
65+
private Gson gson;
66+
private IInputStreamService mService = null;
67+
private final AtomicBoolean mBound = new AtomicBoolean(false); // Flag indicating whether we have called bind on the service
68+
private boolean mDestroyed = false; // Flag indicating if API is destroyed
69+
private SingleSignOnAccount mAccount;
70+
private ApiConnectedListener mCallback;
71+
private Context mContext;
72+
73+
74+
6075
public interface ApiConnectedListener {
6176
void onConnected();
62-
6377
void onError(Exception ex);
6478
}
6579

@@ -72,17 +86,6 @@ public NextcloudAPI(Context context, SingleSignOnAccount account, Gson gson, Api
7286
connectApiWithBackoff();
7387
}
7488

75-
private static final String TAG = NextcloudAPI.class.getCanonicalName();
76-
77-
private Gson gson;
78-
private IInputStreamService mService = null;
79-
private boolean mBound = false; // Flag indicating whether we have called bind on the service
80-
private boolean mDestroyed = false; // Flag indicating if API is destroyed
81-
private SingleSignOnAccount mAccount;
82-
private ApiConnectedListener mCallback;
83-
private Context mContext;
84-
85-
8689
private String getAccountName() {
8790
return mAccount.name;
8891
}
@@ -106,7 +109,7 @@ private void connect() {
106109
}
107110

108111
// Disconnect if connected
109-
if (mBound) {
112+
if (mBound.get()) {
110113
stop();
111114
}
112115

@@ -132,13 +135,13 @@ public void stop() {
132135
mCallback = null;
133136

134137
// Unbind from the service
135-
if (mBound) {
138+
if (mBound.get()) {
136139
if (mContext != null) {
137140
mContext.unbindService(mConnection);
138141
} else {
139142
Log.e(TAG, "Context was null, cannot unbind nextcloud single sign-on service connection!");
140143
}
141-
mBound = false;
144+
mBound.set(false);
142145
mContext = null;
143146
}
144147
}
@@ -152,7 +155,10 @@ public void onServiceConnected(ComponentName className, IBinder service) {
152155
Log.i(TAG, "Nextcloud Single sign-on: onServiceConnected");
153156

154157
mService = IInputStreamService.Stub.asInterface(service);
155-
mBound = true;
158+
mBound.set(true);
159+
synchronized (mBound) {
160+
mBound.notifyAll();
161+
}
156162
mCallback.onConnected();
157163
}
158164

@@ -161,14 +167,32 @@ public void onServiceDisconnected(ComponentName className) {
161167
// This is called when the connection with the service has been
162168
// unexpectedly disconnected -- that is, its process crashed.
163169
mService = null;
164-
mBound = false;
170+
mBound.set(false);
165171

166172
if (!mDestroyed) {
167173
connectApiWithBackoff();
168174
}
169175
}
170176
};
171177

178+
private void waitForApi() throws NextcloudApiNotRespondingException {
179+
synchronized (mBound) {
180+
// If service is not bound yet.. wait
181+
if(!mBound.get()) {
182+
Log.v(TAG, "[waitForApi] - api not ready yet.. waiting [" + Thread.currentThread().getName() + "]");
183+
try {
184+
mBound.wait(10000); // wait up to 10 seconds
185+
186+
// If api is still not bound after 10 seconds.. throw an exception
187+
if(!mBound.get()) {
188+
throw new NextcloudApiNotRespondingException();
189+
}
190+
} catch (InterruptedException ex) {
191+
Log.e(TAG, "WaitForAPI failed", ex);
192+
}
193+
}
194+
}
195+
}
172196

173197
public <T> Observable<T> performRequestObservable(final Type type, final NextcloudRequest request) {
174198
return Observable.fromPublisher(new Publisher<T>() {
@@ -249,7 +273,16 @@ public InputStream performNetworkRequest(NextcloudRequest request) throws Except
249273
* @throws IOException
250274
*/
251275
private ParcelFileDescriptor performAidlNetworkRequest(NextcloudRequest request)
252-
throws IOException, RemoteException {
276+
throws IOException, RemoteException, NextcloudApiNotRespondingException {
277+
278+
// Check if we are on the main thread
279+
if(Looper.myLooper() == Looper.getMainLooper()) {
280+
throw new NetworkOnMainThreadException();
281+
}
282+
283+
// Wait for api to be initialized
284+
waitForApi();
285+
253286
// Log.d(TAG, request.url);
254287
request.setAccountName(getAccountName());
255288
request.setToken(getAccountToken());
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.nextcloud.android.sso.exceptions;
2+
3+
import android.content.Context;
4+
5+
import com.nextcloud.android.sso.R;
6+
import com.nextcloud.android.sso.model.ExceptionMessage;
7+
8+
public class NextcloudApiNotRespondingException extends SSOException {
9+
10+
@Override
11+
public void loadExceptionMessage(Context context) {
12+
this.em = new ExceptionMessage(
13+
context.getString(R.string.nextcloud_files_api_not_responsing_title),
14+
context.getString(R.string.nextcloud_files_api_not_responsing_message)
15+
);
16+
}
17+
18+
}

src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
<string name="nextcloud_files_app_not_supported_title">Error</string>
3131
<string name="nextcloud_files_app_not_supported_message" formatted="true">Your nextcloud files app currently does not support the single sign on feature. Please update it: %1$s</string>
3232

33+
34+
<string name="nextcloud_files_api_not_responsing_title">Error</string>
35+
<string name="nextcloud_files_api_not_responsing_message">Nextcloud files app api is not responding. Please report this issue.</string>
36+
3337
<string name="select_account_unknown_error_toast">Something went wrong.. please try again</string>
3438

3539
</resources>

0 commit comments

Comments
 (0)