Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8124531
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 6, 20262026-06-06T06:28:52+00:00 2026-06-06T06:28:52+00:00

I’m developing a library project that will be integrated into some popular android applications

  • 0

I’m developing a library project that will be integrated into some popular android applications which can be seen in Google Play.

Let assume that user can have two or more applications installed, and each one can integrate my library. The library have some specific code used to detect changes of environment’s state. The state is simply sent to my server. The problem is that environment state processing takes a lot of CPU power, but in a short period of time. Cycles of processing are started by AlarmManager, using “non wake up” broadcasts that launch proper IntentService.

My goal is to implement the library such way, that only one instance integrated into application can do the work. I mean only one library module should act as “active”. If there are more applications installed on user’s device – then they shouldn’t overlap.

How to achieve it? I was thinking about some kind of permission validation, and cross package detection, but couldn’t imagine how to implement it.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-06T06:28:53+00:00Added an answer on June 6, 2026 at 6:28 am

    I have made some additional researches, and managed to find a satisfying solution.
    Here it comes:

    A library has to be developed in a way, that each application which integrates it – publishes broadcast receiver with known action, eg. com.mylib.ACTION_DETECT.

    The library has to have additional Service, that publishes some AIDL interface, which helps with making decision – if current instance of library can be made active. The AIDL can have some useful methods for example getVersion(), isActive(), getUUID().

    The pattern for making decision is: if current instance has higher version number, that other one – it will become active. If current instance has lower version – it will deactivate itself, or stay deactivated if it is already deactivated. If current instance has equal version to other instance, then if other instance is not active, and other library’s uuid is lower (through compareTo method) – it will activate itself. In other condition – it will deactivate itself. This cross checking ensures, that each library will make decision on its own – there will be no ambiguous cases, because each library will fetch required data from published AIDL backed Service of other libary instances in other apps.

    Next step is to prepare an IntentService, that is started each time new package is removed or added, or the application with library is started first time. The IntentService queries all packages for broadcast receivers, which implement com.mylib.ACTION_DETECT.
    Then it iterates through detected packages (rejecting it’s own package), and binds to AIDL backed service of each other instance (the class name of AIDL service will be always the same, only application package would be different). After completing binding – we have clear situation – if applied pattern results “positive” (our instance has better version or higher uuid, or has been active already) then it implies, that other instances figured out themselves as “negative”, and deactivated themselves. Of course the pattern has to be applied on each bound AIDL service.

    I apologize for my bad English.

    Code of working ConfictAvoidance solution:
    IntentService class, that supports binding, so it is also AIDL backed service mentioned above. There is also BroadcastReceiver, which starts conflict checks.

    public class ConflictAvoidance extends IntentService
    {
        private static final String TAG = ConflictAvoidance.class.getSimpleName();
        private static final String PREFERENCES = "mylib_sdk_prefs";
        private static final int VERSION = 1;
        private static final String KEY_BOOLEAN_PRIME_CHECK_DONE = "key_bool_prime_check_done";
        private static final String KEY_BOOLEAN_ACTIVE = "key_bool_active";
        private static final String KEY_LONG_MUUID = "key_long_muuid";
        private static final String KEY_LONG_LUUID = "key_long_luuid";
        private WakeLock mWakeLock;
        private SharedPreferences mPrefs;
    
        public ConflictAvoidance()
        {
            super(TAG);
        }
    
        private final IRemoteSDK.Stub mBinder = new IRemoteSDK.Stub()
        {
            @Override
            public boolean isActive() throws RemoteException
            {
                return mPrefs.getBoolean(KEY_BOOLEAN_ACTIVE, false);
            }
    
            @Override
            public long[] getUUID() throws RemoteException
            {
                return getLongUUID();
            }
    
            @Override
            public int getSdkVersion() throws RemoteException
            {
                return 1;
            }
        };
    
        @Override
        public IBinder onBind(Intent intent)
        {
            return mBinder;
        }
    
        @Override
        public void onCreate()
        {
            //#ifdef DEBUG
            Log.i(TAG, "onCreate()");
            //#endif
            mWakeLock = ((PowerManager) getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
            mWakeLock.acquire();
            mPrefs = getSharedPreferences(PREFERENCES, MODE_PRIVATE);
            super.onCreate();
        }
    
        @Override
        public void onDestroy()
        {
            //#ifdef DEBUG
            Log.i(TAG, "onDestroy()");
            //#endif
            mWakeLock.release();
            super.onDestroy();
        }
    
        @Override
        protected void onHandleIntent(Intent arg)
        {
            //#ifdef DEBUG
            Log.d(TAG, "Conflict check");
            //#endif
            final String packageName = getPackageName();
            //#ifdef DEBUG
            Log.v(TAG, "Current package name: %s", packageName);
            //#endif
            final ArrayList<String> packages = new ArrayList<String>(20);
            final PackageManager man = getPackageManager();
            //#ifdef DEBUG
            Log.v(TAG, "Querying receivers: com.mylib.android.sdk.ACTION_DETECT_LIB");
            //#endif
            final List<ResolveInfo> receivers = man.queryBroadcastReceivers(new Intent("com.mylib.android.sdk.ACTION_DETECT_LIB"), 0);
            for (ResolveInfo receiver : receivers)
            {
                if (receiver.activityInfo != null)
                {
                    final String otherPackageName = receiver.activityInfo.packageName;
                    //#ifdef DEBUG
                    Log.v(TAG, "Checking package: %s", otherPackageName);
                    //#endif
                    if (!packageName.equals(otherPackageName))
                    {
                        packages.add(otherPackageName);
                    }
                }
            }
            if (packages.isEmpty())
            {
                //#ifdef DEBUG
                Log.i(TAG, "No other libraries found");
                //#endif
                setup(true);
            }
            else
            {
                //#ifdef DEBUG
                Log.v(TAG, "Querying other packages");
                //#endif
                final UUID uuid = getUUID();
                for (String pkg : packages)
                {
                    final Intent intent = new Intent();
                    intent.setClassName(pkg, "com.mylib.android.sdk.utils.ConflictAvoidance");
                    final RemoteConnection conn = new RemoteConnection(uuid);
                    try
                    {
                        if (bindService(intent, conn, BIND_AUTO_CREATE))
                        {
                            if (!conn.canActivateItself())
                            {
                                setup(false);
                                return;
                            }
                        }
                    }
                    finally
                    {
                        unbindService(conn);
                    }
                }
                setup(true);
            }
        }
    
        private UUID getUUID()
        {
            final long[] uuid = getLongUUID();
            return new UUID(uuid[0], uuid[1]);
        }
    
        private synchronized long[] getLongUUID()
        {
            if (mPrefs.contains(KEY_LONG_LUUID) && mPrefs.contains(KEY_LONG_MUUID))
            {
                return new long[] { mPrefs.getLong(KEY_LONG_MUUID, 0), mPrefs.getLong(KEY_LONG_LUUID, 0) };
            }
            else
            {
                final long[] uuid = new long[2];
                final UUID ruuid = UUID.randomUUID();
                uuid[0] = ruuid.getMostSignificantBits();
                uuid[1] = ruuid.getLeastSignificantBits();
                mPrefs.edit().putLong(KEY_LONG_MUUID, uuid[0]).putLong(KEY_LONG_LUUID, uuid[1]).commit();
                return uuid;
            }
        }
    
        private void setup(boolean active)
        {
            //#ifdef DEBUG
            Log.v(TAG, "setup(active:%b)", active);
            //#endif
            mPrefs.edit().putBoolean(KEY_BOOLEAN_ACTIVE, active).putBoolean(KEY_BOOLEAN_PRIME_CHECK_DONE, true).commit();
        }
    
        public static StatusInfo getStatusInfo(Context context)
        {
            final SharedPreferences prefs = context.getSharedPreferences(PREFERENCES, MODE_PRIVATE);
            return new StatusInfo(prefs.getBoolean(KEY_BOOLEAN_ACTIVE, false), prefs.getBoolean(KEY_BOOLEAN_PRIME_CHECK_DONE, false));
        }
    
        public static class DetectionReceiver extends BroadcastReceiver
        {
            @Override
            public void onReceive(Context context, Intent intent)
            {
                context.startService(new Intent(context, ConflictAvoidance.class));         
            }       
        }
    
        public static class StatusInfo
        {
            public final boolean isActive;
            public final boolean primeCheckDone;
    
            public StatusInfo(boolean isActive, boolean primeCheckDone)
            {
                this.isActive = isActive;
                this.primeCheckDone = primeCheckDone;
            }       
        }
    
        protected static class RemoteConnection implements ServiceConnection
        {
            private final ConditionVariable var = new ConditionVariable(false);
            private final UUID mUuid;
            private final AtomicReference<IRemoteSDK> mSdk = new AtomicReference<IRemoteSDK>();
    
            public RemoteConnection(UUID uuid)
            {
                super();
                this.mUuid = uuid;
            }
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service)
            {
                //#ifdef DEBUG
                Log.v(TAG, "RemoteConnection.onServiceConnected(%s)", name.getPackageName());
                //#endif
                mSdk.set(IRemoteSDK.Stub.asInterface(service));
                var.open();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name)
            {
                //#ifdef DEBUG
                Log.w(TAG, "RemoteConnection.onServiceDisconnected(%s)", name);
                //#endif
                var.open();
            }
    
            public boolean canActivateItself()
            {
                //#ifdef DEBUG
                Log.v(TAG, "RemoteConnection.canActivateItself()");
                //#endif
                var.block(30000);
                final IRemoteSDK sdk = mSdk.get();
                if (sdk != null)
                {
                    try
                    {
                        final int version = sdk.getSdkVersion();
                        final boolean active = sdk.isActive();
                        final UUID uuid;
                        {
                            final long[] luuid = sdk.getUUID();
                            uuid = new UUID(luuid[0], luuid[1]);
                        }
                        //#ifdef DEBUG
                        Log.v(TAG, "Other library: ver: %d, active: %b, uuid: %s", version, active, uuid);
                        //#endif
                        if (VERSION > version)
                        {
                            return true;
                        }
                        else if (VERSION < version)
                        {
                            return false;
                        }
                        else
                        {
                            if (active)
                            {
                                return false;
                            }
                            else
                            {
                                return mUuid.compareTo(uuid) == 1;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
        }
    
    }
    

    AIDL file:

    package com.mylib.android.sdk;
    
    interface IRemoteSDK
    {
        boolean isActive();
        long[] getUUID();
        int getSdkVersion();
    }
    

    Sample manifest:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.mylib.android.sdk"
        android:versionCode="1"
        android:versionName="1.0" >
        <uses-sdk
            android:minSdkVersion="4"
            android:targetSdkVersion="4" />
            <service
                android:name="com.mylib.android.sdk.utils.ConflictAvoidance"
                android:exported="true" />
            <receiver android:name="com.mylib.android.sdk.utils.ConflictAvoidance$DetectionReceiver" >
                <intent-filter>
                    <action android:name="com.mylib.android.sdk.ACTION_DETECT_LIB" />
                </intent-filter>
                <intent-filter>
                    <action android:name="android.intent.action.PACKAGE_ADDED" />
                    <action android:name="android.intent.action.PACKAGE_REMOVED" />
                    <action android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
                    <action android:name="android.intent.action.PACKAGE_REPLACED" />
                    <data android:scheme="package" />
                </intent-filter>
            </receiver>
        </application>
    </manifest>
    

    Action:

    <action android:name="com.mylib.android.sdk.ACTION_DETECT_LIB" />
    

    It is the common action, which is used to detect other apps with the library.

    Log usage may look weird, but I use custom wrapper, which supports formatting, to decrease StringBuffers overhead when debugging.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have a French site that I want to parse, but am running into
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I need a function that will clean a strings' special characters. I do NOT
That's pretty much it. I'm using Nokogiri to scrape a web page what has
I have just tried to save a simple *.rtf file with some websites and
For some reason, after submitting a string like this Jack’s Spindle from a text
I am trying to understand how to use SyndicationItem to display feed which is
I used javascript for loading a picture on my website depending on which small
I have a jquery bug and I've been looking for hours now, I can't

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.