I try to incorporate Intune app protection policies into my native Android app. I follow instructions from https://learn.microsoft.com/en-us/intune/app-sdk-android. After I changed all classes into their MAM equivalents, my app looped at MAMApplication's onMAMCreate method. My main class derived from MAMApplication class instead of Application class.
Below is my method:
#Override
public void onMAMCreate() {
super.onCreate();
buildObjectGraphAndInject();
setOrmProject(null);
setOrmTemplate(null);
//rest of method
}
And there is a message I got in debug console.
I/MAMInfo: Agent config file does not exist, will use test agent
I/MAMInfo: MAMInfo initialized. Debug=true, UseTestAgent=true,
ManagedDialogDisabled=false, DeprecationDialogDisabled=false,
PolicyRequired=false, MultiIdentityEnabled=false,
FullBackupContent=true, UseDefaultEnrollment=false,
ExceptionOnInit=false
I/MAMWERetryScheduler: task thread waiting for tasks.
I/MAMComponents: Not initializing MAM classes because the MDM package
is not installed.
I/MAMComponents: Not initializing MAM classes because the MDM package
is not installed.
Application do not throw an exception, it just looped at that method and stuck.
I read that MDM is not required to use MAM classes. Have anybody go any idea how to resolve that problem?
Bit of a late answer here - I've only just starting using the SDK myself, but you need to call super.onMAMCreate() which in turn will call super.onCreate() internally.
Related
We've recently started running into crashes in our Android app due to the app being open in multiple processes. Several different errors point towards that. For instance this error:
com.google.firebase.database.DatabaseException: Failed to gain
exclusive lock to Firebase Database's offline persistence. This
generally means you are using Firebase Database from multiple
processes in your app. Keep in mind that multi-process Android apps
execute the code in your Application class in all processes, so you
may need to avoid initializing FirebaseDatabase in your Application
class. If you are intentionally using Firebase Database from multiple
processes, you can only enable offline persistence (i.e. call
setPersistenceEnabled(true)) in one of them.
We are also seeing similar errors from SQLite and H2. This is a new issue and we have not explicitly allowed multiple processes to run. Nothing in our AndroidManifest.xml specifies a custom android:process attribute.
I suspect that some third party library is causing this. How do I identify the root cause of the multiple processes and how do I prevent it?
Another of our apps is connecting to this app via a ContentProvider. At first I thought that it having android:multiprocess="true" was the culprit but changing it to "false" did not help. I still suspect that the other app is somehow triggering the creation of a new process. This is how to the ContentProvider is defined:
<provider
android:name=".DegooContentProvider"
android:authorities="${applicationId}.DegooContentProvider"
android:exported="true"
android:protectionLevel="signature"
android:multiprocess="false">
</provider>
You can check in your applicaition class if there is foreign process. Here is an example:
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
if (!isMainProcess()) {
// Do not call thread unsafe logic. Just return
return;
}
// Thread unsafe logic.
...
}
private boolean isMainProcess() {
int pid = android.os.Process.myPid();
ActivityManager manager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
String currentProcName = processInfo.processName;
if (processInfo.pid == pid) {
if (TextUtils.equals(currentProcName, BuildConfig.APPLICATION_ID)) {
return true;
}
}
}
return false;
}
}
Looks like you are calling the method setPersistenceEnabled() multiple times.
Ensure it is not. You can do this in a several ways.
The preferred method will be to place it only in the onCreate() method of the default Application class if you are extending one.
Another solution will be to place it in the static block of any class.
static {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Or you can even set a static boolean variable say, inFirebaseInstanceInitialized and call setPersistenceEnabled() only if it is not true already.
I have a C++ service, which exposes 2 interfaces:
a. Submit(): For submitting a DistCp job to YARNRM
b. Query(): For querying the status of the application.
This service internally calls a Java client (through JNI), which has 2 static functions:
Submit()
Query()
Submit() does:
DistCp distCp = new DistCp(configuration, distCpOptions);
Job job = distCp.execute();
Parses the "application ID" from the tracking URL and returns it.
Query() does:
Takes "application ID" returned in Submit()
YarnClient yarnClient = YarnClient.createYarnClient();
yarnClient.init(new YarnConfiguration());
yarnClient.start();
yarnClient.getApplicationReport(applicationID);
yarnClient.stop();
The problem I am facing is,
If the first call to the service is Submit(), then all the subsequent calls (both Submit() and Query()) SUCCEED
But, if the first call to the service is Query(), then all the Submit() calls FAIL.
Query() calls succeed under all the conditions.
The Submit() calls fail with errors (1st call, 2nd call and 3rd call below, with different exceptions):
java.util.ServiceConfigurationError: org.apache.hadoop.mapreduce.protocol.ClientProtocolProvider: Provider org.apache.hadoop.mapred.LocalClientProtocolProvider not found
java.util.ServiceConfigurationError: org.apache.hadoop.mapreduce.protocol.ClientProtocolProvider: Provider org.apache.hadoop.mapred.YarnClientProtocolProvider not found
java.io.IOException: Cannot initialize Cluster. Please check your configuration for mapreduce.framework.name and the correspond server addresses.
I debugged the issue and figured out that, when Query() API is called first, then classes LocalClientProtocolProvider and YarnClientProtocolProvider are not loaded. The class loader should load these classes, when Submit() is called. But, that is not happening.
I also observed that, when the Query() API is called first, the Hadoop configuration gets changed and contains lot many default settings related to "mapreduce.*" configuration.
I tried explicit loading using Class.forName(), as soon as the Submit() method is called. But, that did not help either.
When Submit() is called, why does not the class loader load the required classes? Is this the problem with Hadoop configuration or Java class loader? Or is it the problem because I am mixing MapReduce and Yarn APIs?
"mapreduce.framework.name" configuration is set to "yarn".
My environment is Hadoop 2.6.0.
My classpath contains, all the Hadoop jars present in following paths:
a. hadoop/common/
b. hadoop/common/lib
c. hadoop/hdfs/
d. hadoop/hdfs/lib
e. hadoop/mapreduce/
f. hadoop/mapreduce/lib
g. hadoop/yarn/
h. hadoop/yarn/lib
I figured out that, I am mixing Yarn and MapReduce APIs and that is causing class loading problems.
When Query() is called first, it loads all YARN related classes.
For e.g.:
org.apache.hadoop.yarn.client.api.YarnClient from file:/D:/data/hadoop-2
.6.0-SNAPSHOT/share/hadoop/yarn/hadoop-yarn-client-2.6.0-SNAPSHOT.jar
But, the MapReduce related classes are not loaded. For e.g., following class is not loaded:
org.apache.hadoop.mapred.YarnClientProtocolProvider from
file:/D:/data/hdoop-2.6.0-SNAPSHOT/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-2.6.0-SNAPSHOT.jar
So, when the Submit() is called, the class loader assumes that, it has loaded all the required classes. But, classes YarnClientProtocolProvider and LocalClientProtocolProvider are not loaded yet. Hence, the Submit() call fails.
To force the class loader to load all the MapReduce related classes, I added following statements in the constructor for YarnClientWrapper (which is a singleton class and wraps YarnClient).
Cluster cluster = new Cluster(configuration);
cluster.getFileSystem();
cluster.close();
This resolved the issue.
But, cleaner implementation would be to use MapReduce client in Query() instead of YarnClient. This will ensure that, we will not get into class loading issues.
Source at bottom
I am working with a program called "GameMaker:Studio" and I am currently writing a java extension for it for an Android application. I've solved a few other things with research, but now I'm at a true road block.
My Problem is that now that I actually have my GoogleApiClient instance to be created and kind of work, I can't access its callbacks.
class setup:
public class PlayerConnect extends Activity
implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,
RealTimeMessageReceivedListener,
RoomStatusUpdateListener, RoomUpdateListener, OnInvitationReceivedListener{
important imports:
// YYg ** These imports are here to make my class more functional
import ${YYAndroidPackageName}.R;
import ${YYAndroidPackageName}.RunnerActivity;
import com.yoyogames.runner.RunnerJNILib;
// Including
com.google.android.gms.common. --- all the used ones
com.google.android.gms.games. -- all the used ones
As you can see it inherits from class and then implements the interfaces that are used by Google's client class. It imports all the correct imports.
Once I actually create my Client like so,
mGoogleApiClient = new GoogleApiClient.Builder(RunnerActivity.CurrentActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Plus.API).addScope(Plus.SCOPE_PLUS_LOGIN)
.addApi(Games.API).addScope(Games.SCOPE_GAMES)
.build();
I can work with it (slightly). The problem is that although it is functional, the activity belongs to RunnerActivity not my class PlayerConnect. This causes problems because since now that my class can't personally handle the callbacks that I have setup, the RunnerActivity will, and ends up crashing because it doesn't understand. And besides crashing, I can't make my program react to connections or failures.
Is there anyway I can workaround this? If I try using this as the context in the clients Builder, then the client never gets created. I think it has something to do with my activity never actually being created, but I think there's nothing I can do about that because I've tried copying bundles and sharing intents/the such but nothing like that works.
What I'm hoping to be able to do is somehow defer the clients callbacks to my classes' functions since that is the only feasible thing for me to accomplish. Is there anyway I can redirect to my functions? Or the like?
I've read somethings about threading that may be able to create a workaround but I haven't gotten it to work, just crash. Something like a viewhandler?
RunnerActivity.ViewHandler.post( new Runnable() {
public void run() {
onCreate(RunnerActivity.CurrentActivity.getIntent().extras());
onStart();
}
});
Java Source
google docs have a tutorial on how to make an AIDL service. However, when I tried to do the same, I got an error "The method registerCallback(IRemoteInterface) is undefined for the type IRemoteInterface.
I have not seen this "registerCallback" method in any tutorial that I have been googling and my question is why is this not working/why do other places not use it?
I feel like part of my issue is a fundamental misunderstanding about services and their 'callback' to send information to what it is bound to it.
Thanks!
AIDL:
package com.mine.ben;
import com.mine.servicenexus.RelPoint;
interface IRemoteInterface {
Location getLastLocation();
RelPoint getRelPoint();
int logControlActivity(in String text,in int severity);
int getRunningStatus();
}
Updated question:
I get a syntax error in my AIDL file when i add
void registerCallback(IRemoteServiceCallback);
void unregisterCallback(IRemoteServiceCallback);
I have cleaned my workspace and it builds automatically. Is this a problem with the gen file?
Few lines from my application:
interface IGpsService {
Bundle getNavigationMessage();
void resetStatistics();
void recordingEnable(boolean recordingEnabled, boolean continueLastTrack);
void registerCallback(IGpsChanged cb);
void unregisterCallback(IGpsChanged cb);
boolean isRecordingEnabled();
void setGhost(int trackId);
void startGhost();
void sendUserEvent(int eventId);
}
second file for calback interface itself:
interface IGpsChanged{
oneway void onLocationChanged(out Bundle message);
}
Best of all - usually you do not need those .aidl definitions. This is necessary only when exposing service methods outside of the application.
It's also helpful to understand how it works - forst aidl defines basic service's methods. registerCallback is not a "special" method, it's as oridinary as any other, just enables defining callbacks for two-way communication (in this particular case - to send some position info from sesrvice to binded activity (or other component).
As you mentioned in comment - you do not want to create service, just consume some service from outside of application. In that case you need those external aidl file, not the one written by you. Stubs for consuming service's method will be generated in the /gen directory.
google docs have a tutorial on how to make an AIDL service.
That is not a tutorial. It is just ordinary documentation.
However, when I tried to do the same, I got an error "The method registerCallback(IRemoteInterface) is undefined for the type IRemoteInterface.
That is because you do not have a method named registerCallback() in your AIDL.
I have not seen this "registerCallback" method in any tutorial
It is not in a tutorial. The only occurrences of registerCallback() in the Web page that you linked to are from "some sample code demonstrating calling an AIDL-created service, taken from the Remote Service sample in the ApiDemos project". The ApiDemos project is in your SDK installation, if you elected to download sample code from the SDK Manager.
Code example from AIDL guide that you have referenced is taken from the Remote Service sample in the ApiDemos project.
And registerCallback() in it is implemented by using android.os.RemoteCallbackList<E extends android.os.IInterface> object.
Make an .aidl file like:
package com.example;
oneway interface IRemoteServiceCallback {
/**
* Goes to client.
*/
void valueChanged(int value);
}
Make another .aidl file where you import this interface and use it as a method's parameter like:
package com.example;
import com.example.IRemoteServiceCallback;
interface IRemoteService {
/**
* Goes to service.
*/
void registerCallback(IRemoteServiceCallback cb);
}
Generate code from .aidl on both sides.
Implement IRemoteService.Stub in service and return it in onBind()
Implement IRemoteServiceCallback.Stub in client and pass it in ServiceConnection's onServiceConnected() callback to the received from IRemoteService.Stub.asInterface() instance of IRemoteService.
Now you service can talk back to the client over the passed IRemoteServiceCallback implementation.
i am a newbie.Please explain what all things are passed through a context.Like when constructing an object for the following class..
public class myclass{
public myclass (Context context){....}
}
You get a lot of possibilities to check for or change System or application properties.
You will find a detailed version of all the functions that are available with the context in the api documentation of android:
http://developer.android.com/reference/android/content/Context.html
So you will be able for example to start a service (to run part of the application in the background) through context.startService(Intent service). You'll need to pass an Intent (if you don't know what an intent is I would read the Dev Guide: http:**developer.android.com/guide/topics/fundamentals.html first. You could do that anyway, there are plenty of good descriptions and examples.).
Sorry for the crippled link, I'm not allowed to post more than one link per post...