Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37a40c24 authored by Amith Yamasani's avatar Amith Yamasani
Browse files

App Standby : Association between content providers and their sync adapter

Set sync adapters to active if the associated content providers are used
at foreground process state.

Minimize how frequently published content providers are reported by
keeping track of last reported time.

Also cache sync adapters associated with an authority in SyncManager.

Bug: 21785111
Change-Id: Ic2c8cb6a27f005d1a1d0aad21d36b1510160753a
parent b0ff3a6c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -53,6 +53,14 @@ public abstract class UsageStatsManagerInternal {
     */
    public abstract void reportConfigurationChange(Configuration config, int userId);

    /**
     * Reports that a content provider has been accessed by a foreground app.
     * @param name The authority of the content provider
     * @param pkgName The package name of the content provider
     * @param userId The user in which the content provider was accessed.
     */
    public abstract void reportContentProviderUsage(String name, String pkgName, int userId);

    /**
     * Prepares the UsageStatsService for shutdown.
     */
+15 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.util.Log;

import dalvik.system.CloseGuard;

import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;

import java.io.File;
@@ -57,6 +58,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

@@ -1935,6 +1937,19 @@ public abstract class ContentResolver {
        }
    }

    /**
     * @hide
     * Returns the package names of syncadapters that match a given user and authority.
     */
    public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
            int userId) {
        try {
            return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
        } catch (RemoteException e) {
        }
        return ArrayUtils.emptyArray(String.class);
    }

    /**
     * Check if the provider should be synced when a network tickle is received
     * <p>This method requires the caller to hold the permission
+2 −0
Original line number Diff line number Diff line
@@ -143,6 +143,8 @@ interface IContentService {
    SyncAdapterType[] getSyncAdapterTypes();
    SyncAdapterType[] getSyncAdapterTypesAsUser(int userId);

    String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId);

    /**
     * Returns true if there is currently a operation for the given account/authority or service
     * actively being processed.
+62 −0
Original line number Diff line number Diff line
@@ -20,12 +20,19 @@ import android.content.pm.RegisteredServicesCache;
import android.content.pm.XmlSerializerAndParser;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

/**
 * A cache of services that export the {@link android.content.ISyncAdapter} interface.
@@ -39,6 +46,10 @@ public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType>
    private static final String ATTRIBUTES_NAME = "sync-adapter";
    private static final MySerializer sSerializer = new MySerializer();

    @GuardedBy("mServicesLock")
    private SparseArray<ArrayMap<String,String[]>> mAuthorityToSyncAdapters
            = new SparseArray<>();

    public SyncAdaptersCache(Context context) {
        super(context, SERVICE_INTERFACE, SERVICE_META_DATA, ATTRIBUTES_NAME, sSerializer);
    }
@@ -76,6 +87,57 @@ public class SyncAdaptersCache extends RegisteredServicesCache<SyncAdapterType>
        }
    }

    @Override
    protected void onServicesChangedLocked(int userId) {
        synchronized (mServicesLock) {
            ArrayMap<String,String[]> adapterMap = mAuthorityToSyncAdapters.get(userId);
            if (adapterMap != null) {
                adapterMap.clear();
            }
        }

        super.onServicesChangedLocked(userId);
    }

    public String[] getSyncAdapterPackagesForAuthority(String authority, int userId) {
        synchronized (mServicesLock) {
            ArrayMap<String,String[]> adapterMap = mAuthorityToSyncAdapters.get(userId);
            if (adapterMap == null) {
                adapterMap = new ArrayMap<>();
                mAuthorityToSyncAdapters.put(userId, adapterMap);
            }
            // If the mapping exists, return it
            if (adapterMap.containsKey(authority)) {
                return adapterMap.get(authority);
            }
            // Create the mapping and cache it
            String[] syncAdapterPackages;
            final Collection<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> serviceInfos;
            serviceInfos = getAllServices(userId);
            ArrayList<String> packages = new ArrayList<>();
            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> serviceInfo : serviceInfos) {
                if (authority.equals(serviceInfo.type.authority)
                        && serviceInfo.componentName != null) {
                    packages.add(serviceInfo.componentName.getPackageName());
                }
            }
            syncAdapterPackages = new String[packages.size()];
            packages.toArray(syncAdapterPackages);
            adapterMap.put(authority, syncAdapterPackages);

            return syncAdapterPackages;
        }
    }

    @Override
    protected void onUserRemoved(int userId) {
        synchronized (mServicesLock) {
            mAuthorityToSyncAdapters.remove(userId);
        }

        super.onUserRemoved(userId);
    }

    static class MySerializer implements XmlSerializerAndParser<SyncAdapterType> {
        public void writeAsXml(SyncAdapterType item, XmlSerializer out) throws IOException {
            out.attribute(null, "authority", item.authority);
+10 −2
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ public abstract class RegisteredServicesCache<V> {
    private final String mAttributesName;
    private final XmlSerializerAndParser<V> mSerializerAndParser;

    private final Object mServicesLock = new Object();
    protected final Object mServicesLock = new Object();

    @GuardedBy("mServicesLock")
    private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2);
@@ -232,6 +232,7 @@ public abstract class RegisteredServicesCache<V> {
        synchronized (mServicesLock) {
            final UserServices<V> user = findOrCreateUserLocked(userId);
            user.services = null;
            onServicesChangedLocked(userId);
        }
    }

@@ -489,11 +490,16 @@ public abstract class RegisteredServicesCache<V> {
                }
            }
            if (changed) {
                onServicesChangedLocked(userId);
                writePersistentServicesLocked(user, userId);
            }
        }
    }

    protected void onServicesChangedLocked(int userId) {
        // Feel free to override
    }

    /**
     * Returns true if the list of changed uids is null (wildcard) or the specified uid
     * is contained in the list of changed uids.
@@ -687,8 +693,10 @@ public abstract class RegisteredServicesCache<V> {

    @VisibleForTesting
    protected void onUserRemoved(int userId) {
        synchronized (mServicesLock) {
            mUserServices.remove(userId);
        }
    }

    @VisibleForTesting
    protected List<UserInfo> getUsers() {
Loading