I am working on a project which runs on aosp. I added a system service to aosp. I run this service with using adb shell "service call" command successfully. While creating service, I applied following ways.
Added an aidl file
Added a .java file which derived from aidl
Added jni file.
After creating service, I wrote an basic android app. I want to call this service from this android app. How I can call this service from android app.
Create a service manager in: frameworks/base/core/java/android/os/MySerManager.java next to the .aidl interface definition.
In frameworks/base/core/java/android/content/Context.java
search for a simple service like VIBRATOR_SERVICE and add MYSER_SERIVCE to every occurrence.
In particular add: public static final String MYSER_SERVICE = "myser";
Do the same in frameworks/base/core/java/android/app/SystemServiceRegistry.java
making sure to add:
import android.os.MySerManager;
registerService(Context.MYSER_SERVICE, MySerManager.class,
new CachedServiceFetcher<MySerManager>() {
#Override
public MySerManager createService(ContextImpl ctx) {
return new MySerManager();
}});
This service manager can be used outside of the AOSP by building the sdk: https://android.googlesource.com/platform/sdk/+/master/docs/howto_build_SDK.txt
And within the AOSP by getting the system service from the Context:
MySerManager mySerManager = (MySerManager)getSystemService(Context.MYSER_SERVICE);
I managed to solve how system service calls from android app. After compiling aosp, classes.jar in framework_intermediates file is created to out/target/common/obj/JAVA_LIBRARIES. I added classes.jar to my android app and I used following codes.
IBinder binder = ServiceManager.getService("my_service");
IMyService myService = IMyService.Stub.asInterface(binder);
int result = myService.myFunction();
Related
We have a shared library that contains version info and is referenced by all our projects in our Visual Studio Solution.
For the most part, we can reference the version string from every project and the dll reflect the info accordingly.
My issue here is, with our Android application (xamarin based). It has a manifest file which contains the versionName and versionCode.
How can we make those values in our android manifest file read from our shared project?
My understanding is that, it is not possible. Because
The manifest file presents essential information about your app to the Android system, information the system must have before it can run any of the app's code.
From Google's documentation
So this is a file that is required before the App builds.
C# Code in Shared Project (SAP/PCL) is ready to be used only after successful Compilation. So logically setting the Version Code and Version Name in Android Manifest File from Shared logic is not possible.
Another standard approach would be to set it from String Resource (XML) file in Android. You may have to copy and paste the value from Shared Project to strings.xml file and refer it in manifest, like
#string/versionCode
Note: I do not know anything about xamarin.
In java you can get the versioninfo from the manifest like this
public static String getAppVersionName(final Context context) {
try {
final String versionName = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0).versionName;
return versionName;
} catch (final NameNotFoundException e) {
}
return null;
}
I assume that xamarin has some mechanism to call PackageManager to get Packageinfo, too
You could do this by using a Dependency Service. Here's a great article on them: https://developer.xamarin.com/guides/xamarin-forms/dependency-service/
The idea would be your Dependency Service would expose the Android specific information to the shared code library.
For instance you might have an interface in your common code declared such as:
public interface IPlatformVersionInfo
{
string GetOSVersion ();
}
Now, in your Android library you would implement it:
public class PlatformVersionInfo : IPlatformVersionInfo
{
public string GetOSVersion () {
return Android.OS.Build.VERSION.SdkInt.ToString ();
}
}
Finally, in your common code you would use your dependency service of choice to invoke an instance of it:
var osVersion = DependencyService.Get<IPlatformVersionInfo>().GetOSVersion ();
Of course this is somewhat pseudo-code and depending what dependency service you choose the code may look a bit different.
I'm using the book "Embedded Android".
I'm making a new System Service using AOSP(4.0.3_r1).
I want my system service to be registered in frameworks/base/core/java/android/content/app/ContextImpl.java so that I can use it through getSystemService() method.
The problem is, I can't find the app folder under content:androidroot/frameworks/base/core/java/android/content/app/ContextImpl.java
But, I found it in:androidroot/frameworks/base/core/java/android/app/ContextImpl.java
Are these 2 files the same? or is it just missing(the content/app folder)?
Any idea on what to do?
Karim wrote his book mostly orienting on Android 2.3.4 version. Something can be changed from this time. This is an example what has been changed.
Are these 2 files the same? or is it just missing(the content/app folder)?
These are the same files.
Any idea on what to do?
As I said the implementation has been changed. I looked into the code and here what you can change to make your code working (I can only suppose because I did not actually build my code). In the static block of ContextImpl class you need to add the following code:
registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(OPERSYS_SERVICE);
IOpersysService service = IOpersysService.Stub.asInterface(b);
return new OpersysManager(service);
}});
You need to use SystemServer which holds all system services' names.
You should check this link out:
http://processors.wiki.ti.com/index.php/Android-Adding_SystemService
[The background]
I have been able to use the instrumentation in Android test projects. But now, I am trying to use instrumentation in normal Android app in order to do some automatic GUI control. For example, there is an app X in which instrumentation is used to start app Y and to send virtual keys/touch/click events into app Y. I successfully did it with one activity and one class derived from Instrumentation. These 2 classes are created in one app project. The activity is like this:
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
...
String pack = new String("com.example.appX.MainActivity");
ComponentName name = new ComponentName(MainActivity.this,
FilterInstrumentation.class);
Bundle arguments = new Bundle();
arguments.putString("package", pack);
startInstrumentation(name, null, arguments);
...
}
}
The instrumentation sub class is like this:
public class FilterInstrumentation extends Instrumentation {
public void onStart(){
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName(getTargetContext(), pack);
Activity activity = startActivitySync(intent);
}
...
}
[The problem]
The activity and the instrumentation are working successfully. A TCP server is also made to receive commands from external network in order to control the instrument's behaviors. I met the following 2 problems:
Problem 1 when the TCP server in the activity: Sockets can be created but the activity and the instrument can't talk to each other because "startInstrumentation()" is starting the instrument in a new standalone process. The activity can't get the instance of the "FilterInstrumentation" class. Commands received by the TCP server can't be sent to the instrument easily.
Problem 2 when the TCP server in the FilterInstrumentation. It will failed to create sockets due to the permission issue as "java.net.SocketException: socket failed: EACCES (Permission denied)". FilterInstrumentation is running in a dynamically created process, I can't control the permission by Manifest.xml file.
It seems that the test framework of Android can run an instrument in the same process but I don't know how to do this within my code without test framework used.
Can any master give any helpful info on this?
Thanks in advance.
I have a library project and different sub-projects with images/teksts etc, that use this library. I want every app (sub-project) to have it's own crashreport formkey, but I can only set it once, statically in the library's Application class, using "#ReportsCrashes(formKey=..."
Is there another way to set it up, so the formkey can differ for every app I create using this library?
Found the solution. You'll need the very latest version of Acra, and do exactly this:
#ReportsCrashes(formKey = "")
public class RootApplication extends Application {
#Override
public void onCreate() {
ACRA.getConfig().setFormKey(
getResources().getString(R.string.acra_form_key));
ACRA.init(this);
ACRA.getErrorReporter().setReportSender(new HockeySender());
super.onCreate();
}
}
Of course you only use a hockeysender when you use hockeyapp.
I've stuck a total wall with the AIDL interfacing. I've an app which has to be controlled via 3rd party application (I've enough control over this so I can ask them to implement what ever I need into their activity)
Originally my app was also an activity with interface and everything but I've changed it to be a background service and for testing, I created a dummy app which manages to start the service app to the background.
Now I would like a way to request method calls from the service (mainly; start, stop, sendData). I've created the .aidl files for both apps. The aidl file implements only one method (this is courtesy of some other question here.)
package foo.testapp;
interface IScript
{
String executeScript(String script);
}
while the other aidl is same except the package is "foo.otherapp". The implementations I've found online had same package for both aidl files, but for me this causes an error (guess this is just a problem on my part since I hate namespaces and packages so I often just name them badly, if it's important to change them, I can do it)
The plan was to use this method to send a string to the service and just have a switch over predefined strings to call a correct method ( could also just implement three different methods if it improves the usage).
Anyway... I can't get the aidl to connect, I get error "Unable to start service intent
{act=foo.testapp.IScript } : not found
I would this guess has something to do with my misunderstandings ie. packagenames or so)
this is the implementation in my test activity app
private final IScript.Stub mBinder = new IScript.Stub()
{
#Override
public String executeScript(String script) throws RemoteException
{
// TODO Auto-generated method stub
}
};
IScript mService = null;
private ServiceConnection mConnection = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder service)
{
mService = IScript.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName className)
{
mService = null;
}
};
Then in OnCreate() method I'll do this:
bindService(new Intent(IScript.class.getName()),
mConnection, Context.BIND_AUTO_CREATE);
In service class I have this;
#Override
public IBinder onBind(Intent intent)
{
// Select the interface to return. If your service only implements
// a single interface, you can just return it here without checking
// the Intent.
if (IScript.class.getName().equals(intent.getAction()))
{
return mBinder;
}
return null;
}
/**
* The IRemoteInterface is defined through IDL
*/
private final IScript.Stub mBinder = new IScript.Stub()
{
#Override
public String executeScript(String script) throws RemoteException
{
if (script == "test")
{
return "foo";
}
return "fail";
}
};
And finally the manifest files;
well actually, I've no idea if I have to add something into manifest files when dealing with the aidl. In the one example I saw this;
<intent-filter>
<action android:name="foo.otherapp.IScript" />
</intent-filter>
and
<intent-filter>
<action android:name="foo.testapp.IScript" />
</intent-filter>
I would guess that the errors could be anywhere. I've been trying to set this up with chewing gum and band-aids. Guess I've just misunderstood some basic concept of this.
Anyway, any help is welcome.
Thanks in advance!
I decided to answer my own question since I found an exact solution.
My Life With Android
Everything worked just by copy pasting the source and changing the package names and function names correctly (assuming you're implementing this into your own project)
Source from client folder goes to the client activity and serviceimpl goes to service. I didn't need the 'Service activity', so I left it out ( and it doesn't really seem to be invoked anyway).
I don't have enough reputation to post multiple links, so you can get the source from the top of the page.
"Update: please check out the updated example program for Android SDK 1.5."
I struggled with this too. You are correct in your guess that the RemoteInterface.aidl needs to have the same package name in both the service and the test app - so where do you put it!?
If you are developing in Eclipse then the trick is to have a common source folder (common to both projects) Make this folder outside of both projects and in the build properties/source, click 'link source' and browse to the location of the common source. (You can call it any name you want) Do this in both projects and put the interface.aidl in there. It will appear in both projects' Package Explorer and when you change it in one project, the other will get updated too.
In the common source folder I put the interface.aidl in a package with the same name as the service.
If you are using Ant to build, the it gets a bit tricky as the default ant_rules.xml doesn't support two aidl folders, and you'll have to modify your build.xml quite a bit add a new target and all its dependencies.
I got my project going by adapting the samples form Chapter 17 from the 'download source' here:
link text