19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
177a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeypackage com.android.server.content;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
197a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.Manifest;
207a1355950172b7a549820e9a2cd4a9b2099ec32fDianne Hackbornimport android.accounts.Account;
2116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tateimport android.app.ActivityManager;
227a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.ContentResolver;
237a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.Context;
247a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.IContentService;
257a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.ISyncStatusObserver;
267a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.PeriodicSync;
277a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.SyncAdapterType;
287a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.SyncInfo;
29fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williamsimport android.content.SyncRequest;
307a96c39c510923ef73bbb06ab20109f0168b8eb1Jeff Sharkeyimport android.content.SyncStatusInfo;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.IContentObserver;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.sqlite.SQLiteException;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
341b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport android.os.Binder;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
37231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackbornimport android.os.Parcel;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
40e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrillimport android.os.SystemProperties;
41f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
42632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williamsimport android.text.TextUtils;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
44fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williamsimport android.util.Pair;
456009459405bbaa42054c9746c6339b48962c7753Jeff Sharkeyimport android.util.Slog;
461b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport android.util.SparseIntArray;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
5016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tateimport java.security.InvalidParameterException;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
521b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport java.util.Collections;
531b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackbornimport java.util.Comparator;
54c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintanaimport java.util.List;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide}
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
59231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackbornpublic final class ContentService extends IContentService.Stub {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "ContentService";
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mFactoryTest;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final ObserverNode mRootNode = new ObserverNode("");
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SyncManager mSyncManager = null;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Object mSyncManagerLock = new Object();
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SyncManager getSyncManager() {
68e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill        if (SystemProperties.getBoolean("config.disable_network", false)) {
69e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill            return null;
70e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill        }
71e4d9a01bfc7451afff1ed399a5801c7aa2af2831Dan Morrill
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(mSyncManagerLock) {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (SQLiteException e) {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Can't create SyncManager", e);
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mSyncManager;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP,
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "caller doesn't have the DUMP permission");
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSyncManager == null) {
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("No SyncManager created!  (Disk full?)");
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mSyncManager.dump(fd, pw);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
971b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            pw.println();
981b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            pw.println("Observer tree:");
991b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            synchronized (mRootNode) {
1001b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                int[] counts = new int[2];
1011b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                final SparseIntArray pidCounts = new SparseIntArray();
1021b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                mRootNode.dumpLocked(fd, pw, args, "", "  ", counts, pidCounts);
1031b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.println();
1041b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                ArrayList<Integer> sorted = new ArrayList<Integer>();
1051b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<pidCounts.size(); i++) {
1061b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    sorted.add(pidCounts.keyAt(i));
1071b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
1081b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                Collections.sort(sorted, new Comparator<Integer>() {
1091b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    @Override
1101b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    public int compare(Integer lhs, Integer rhs) {
1111b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        int lc = pidCounts.get(lhs);
1121b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        int rc = pidCounts.get(rhs);
1131b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        if (lc < rc) {
1141b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            return 1;
1151b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        } else if (lc > rc) {
1161b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            return -1;
1171b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        }
1181b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        return 0;
1191b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    }
1201b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn
1211b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                });
1221b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<sorted.size(); i++) {
1231b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    int pid = sorted.get(i);
1241b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    pw.print("  pid "); pw.print(pid); pw.print(": ");
1251b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            pw.print(pidCounts.get(pid)); pw.println(" observers");
1261b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
1271b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.println();
1281b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.print(" Total number of nodes: "); pw.println(counts[0]);
1291b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.print(" Total number of observers: "); pw.println(counts[1]);
1301b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
136231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    @Override
137231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
138231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            throws RemoteException {
139231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
140231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            return super.onTransact(code, data, reply, flags);
141231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } catch (RuntimeException e) {
142231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            // The content service only throws security exceptions, so let's
143231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            // log all others.
144231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (!(e instanceof SecurityException)) {
145164371fb759bad6854570af0fca60d9a01e17235Dianne Hackborn                Slog.wtf(TAG, "Content Service Crash", e);
146231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
147231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            throw e;
148231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
149231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
150231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*package*/ ContentService(Context context, boolean factoryTest) {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFactoryTest = factoryTest;
15426ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    }
15526ff6626fc4ee0ae46f01ad309b366921da589feKenny Root
15626ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    public void systemReady() {
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        getSyncManager();
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    /**
16116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * Register a content observer tied to a specific user's view of the provider.
16216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * @param userHandle the user whose view of the provider is to be observed.  May be
16316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     the calling user without requiring any permission, otherwise the caller needs to
16416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and
16516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     USER_CURRENT are properly handled; all other pseudousers are forbidden.
16616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     */
16716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    @Override
16816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    public void registerContentObserver(Uri uri, boolean notifyForDescendants,
16916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            IContentObserver observer, int userHandle) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (observer == null || uri == null) {
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("You must pass a valid uri and observer");
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
17416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        final int callingUser = UserHandle.getCallingUserId();
17516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (callingUser != userHandle) {
17616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
17716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    "no permission to observe other users' provider view");
17816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
17916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
18016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (userHandle < 0) {
18116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            if (userHandle == UserHandle.USER_CURRENT) {
18216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                userHandle = ActivityManager.getCurrentUser();
18316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            } else if (userHandle != UserHandle.USER_ALL) {
18416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                throw new InvalidParameterException("Bad user handle for registerContentObserver: "
18516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        + userHandle);
18616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            }
18716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
18816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mRootNode) {
19016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
19116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    Binder.getCallingUid(), Binder.getCallingPid(), userHandle);
19243a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato            if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
19316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    " with notifyForDescendants " + notifyForDescendants);
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    public void registerContentObserver(Uri uri, boolean notifyForDescendants,
19816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            IContentObserver observer) {
19916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        registerContentObserver(uri, notifyForDescendants, observer,
20016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                UserHandle.getCallingUserId());
20116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    }
20216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unregisterContentObserver(IContentObserver observer) {
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (observer == null) {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("You must pass a valid observer");
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mRootNode) {
208002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana            mRootNode.removeObserverLocked(observer);
20943a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato            if (false) Log.v(TAG, "Unregistered observer " + observer);
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    /**
21416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * Notify observers of a particular user's view of the provider.
21516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     * @param userHandle the user whose view of the provider is to be notified.  May be
21616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     the calling user without requiring any permission, otherwise the caller needs to
21716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and
21816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     *     USER_CURRENT are properly interpreted; no other pseudousers are allowed.
21916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate     */
22016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    @Override
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void notifyChange(Uri uri, IContentObserver observer,
22216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            boolean observerWantsSelfNotifications, boolean syncToNetwork,
22316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            int userHandle) {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Log.isLoggable(TAG, Log.VERBOSE)) {
22516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle
22616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    + " from observer " + observer + ", syncToNetwork " + syncToNetwork);
22716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
22816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
22916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        // Notify for any user other than the caller's own requires permission.
23016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        final int callingUserHandle = UserHandle.getCallingUserId();
23116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (userHandle != callingUserHandle) {
23216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
23316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    "no permission to notify other users");
23416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        }
23516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
23616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        // We passed the permission check; resolve pseudouser targets as appropriate
23716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        if (userHandle < 0) {
23816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            if (userHandle == UserHandle.USER_CURRENT) {
23916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                userHandle = ActivityManager.getCurrentUser();
24016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            } else if (userHandle != UserHandle.USER_ALL) {
24116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                throw new InvalidParameterException("Bad user handle for notifyChange: "
24216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        + userHandle);
24316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
24657286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert        final int uid = Binder.getCallingUid();
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mRootNode) {
253002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
25416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        userHandle, calls);
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numCalls = calls.size();
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<numCalls; i++) {
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverCall oc = calls.get(i);
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
260655e66bceba7595a2b80e7a328433e6ed5dc28a9Jeff Brown                    oc.mObserver.onChange(oc.mSelfChange, uri);
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException ex) {
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    synchronized (mRootNode) {
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.w(TAG, "Found dead observer, removing");
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        IBinder binder = oc.mObserver.asBinder();
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final ArrayList<ObserverNode.ObserverEntry> list
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                = oc.mNode.mObservers;
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int numList = list.size();
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        for (int j=0; j<numList; j++) {
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ObserverNode.ObserverEntry oe = list.get(j);
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (oe.observer.asBinder() == binder) {
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                list.remove(j);
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                j--;
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                numList--;
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (syncToNetwork) {
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SyncManager syncManager = getSyncManager();
284ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                if (syncManager != null) {
28557286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert                    syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
28604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            uri.getAuthority());
287ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                }
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    public void notifyChange(Uri uri, IContentObserver observer,
29516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            boolean observerWantsSelfNotifications, boolean syncToNetwork) {
29616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
29716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                UserHandle.getCallingUserId());
29816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate    }
29916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Hide this class since it is not part of api,
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but current unittest framework requires it to be public
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final class ObserverCall {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ObserverNode mNode;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IContentObserver mObserver;
30986de0590b94bcce27e3038c27464bed510bb564aJeff Brown        final boolean mSelfChange;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31186de0590b94bcce27e3038c27464bed510bb564aJeff Brown        ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange) {
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mNode = node;
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mObserver = observer;
31486de0590b94bcce27e3038c27464bed510bb564aJeff Brown            mSelfChange = selfChange;
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
318fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
319ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void requestSync(Account account, String authority, Bundle extras) {
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ContentResolver.validateSyncExtrasBundle(extras);
321f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
32257286f970641493b315b0b42aba7ac6b672cc8b8Alon Albert        int uId = Binder.getCallingUid();
32304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SyncManager syncManager = getSyncManager();
329ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            if (syncManager != null) {
330fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                syncManager.scheduleSync(account, userId, uId, authority, extras,
331fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        0 /* no delay */, 0 /* no delay */,
3324a6679b97e0285c5b65ec5c0d9080ff90d3e9e81Fred Quintana                        false /* onlyThoseWithUnkownSyncableState */);
333ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
340fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * Request a sync with a generic {@link android.content.SyncRequest} object. This will be
341fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * either:
342fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     *   periodic OR one-off sync.
343fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * and
344fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     *   anonymous OR provider sync.
345fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * Depending on the request, we enqueue to suit in the SyncManager.
346632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams     * @param request The request object. Validation of this object is done by its builder.
347fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     */
348fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
349fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    public void sync(SyncRequest request) {
350fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        Bundle extras = request.getBundle();
351fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        long flextime = request.getSyncFlexTime();
352fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        long runAtTime = request.getSyncRunTime();
353fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        int userId = UserHandle.getCallingUserId();
354fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        int uId = Binder.getCallingUid();
355fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams
356fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // This makes it so that future permission checks will be in the context of this
357fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        // process rather than the caller's process. We will restore this before returning.
358fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        long identityToken = clearCallingIdentity();
359fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        try {
360fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            SyncManager syncManager = getSyncManager();
361fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            if (syncManager != null) {
362fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                if (request.hasAuthority()) {
363fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                    // Sync Adapter registered with the system - old API.
3646222288bfbae46550b4914ef1eb12c69dc1f716cMatthew Williams                    final  Account account = request.getAccount();
3656222288bfbae46550b4914ef1eb12c69dc1f716cMatthew Williams                    final String provider = request.getProvider();
366fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                    if (request.isPeriodic()) {
367fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        mContext.enforceCallingOrSelfPermission(
368fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                                Manifest.permission.WRITE_SYNC_SETTINGS,
369fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                                "no permission to write the sync settings");
370fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        if (runAtTime < 60) {
371fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                            Slog.w(TAG, "Requested poll frequency of " + runAtTime
372fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                                    + " seconds being rounded up to 60 seconds.");
373fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                            runAtTime = 60;
374fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        }
375fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        PeriodicSync syncToAdd =
376fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                                new PeriodicSync(account, provider, extras, runAtTime, flextime);
377fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
378fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                    } else {
379fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        long beforeRuntimeMillis = (flextime) * 1000;
380fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        long runtimeMillis = runAtTime * 1000;
381fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                        syncManager.scheduleSync(
382fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                                account, userId, uId, provider, extras,
383fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                                beforeRuntimeMillis, runtimeMillis,
384fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                                false /* onlyThoseWithUnknownSyncableState */);
385fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                    }
386fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                } else {
3876222288bfbae46550b4914ef1eb12c69dc1f716cMatthew Williams                    Log.w(TAG, "Unrecognised sync parameters, doing nothing.");
388fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                }
389fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            }
390fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        } finally {
391fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            restoreCallingIdentity(identityToken);
392fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams        }
393fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    }
394fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams
395fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    /**
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Clear all scheduled sync operations that match the uri and cancel the active sync
397ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * if they match the authority and account, if they are present.
398ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param account filter the pending and active syncs to cancel using this account
399ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @param authority filter the pending and active syncs to cancel using this authority
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
401fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
402ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void cancelSync(Account account, String authority) {
403632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (authority != null && authority.length() == 0) {
404632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Authority must be non-empty");
405632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
40604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
407632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This makes it so that future permission checks will be in the context of this
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // process rather than the caller's process. We will restore this before returning.
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identityToken = clearCallingIdentity();
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            SyncManager syncManager = getSyncManager();
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (syncManager != null) {
41404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                syncManager.clearScheduledSyncOperations(account, userId, authority);
41504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                syncManager.cancelActiveSync(account, userId, authority);
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restoreCallingIdentity(identityToken);
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
422ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    /**
423ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * Get information about the SyncAdapters that are known to the system.
424ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     * @return an array of SyncAdapters that have registered with the system
425ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana     */
426fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
427ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public SyncAdapterType[] getSyncAdapterTypes() {
428ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        // This makes it so that future permission checks will be in the context of this
429ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        // process rather than the caller's process. We will restore this before returning.
4306ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final int userId = UserHandle.getCallingUserId();
4316ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final long identityToken = clearCallingIdentity();
432ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        try {
433ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            SyncManager syncManager = getSyncManager();
4346ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            return syncManager.getSyncAdapterTypes(userId);
435ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        } finally {
436ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana            restoreCallingIdentity(identityToken);
437ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana        }
438ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    }
439b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
440fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
441ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public boolean getSyncAutomatically(Account account, String providerName) {
442231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
443231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync settings");
44404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
445632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
446231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
447231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
448231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
449231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
450ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                return syncManager.getSyncStorageEngine().getSyncAutomatically(
45104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName);
452231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
453231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
454231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
455231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
456231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
457231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
458231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
459fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
460ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void setSyncAutomatically(Account account, String providerName, boolean sync) {
461632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (TextUtils.isEmpty(providerName)) {
462632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Authority must be non-empty");
463632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
464231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
465231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to write the sync settings");
46604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
467632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
468231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
469231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
470231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
471231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
472ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                syncManager.getSyncStorageEngine().setSyncAutomatically(
47304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName, sync);
474231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
475231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
476231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
477231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
478231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
479231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
480632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams    /** Old API. Schedule periodic sync with default flex time. */
481fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
482c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    public void addPeriodicSync(Account account, String authority, Bundle extras,
483c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            long pollFrequency) {
484632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (account == null) {
485632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Account must not be null");
486632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
487632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (TextUtils.isEmpty(authority)) {
488632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Authority must not be empty.");
489632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
490c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
491c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                "no permission to write the sync settings");
49204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
493632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
49451366be80fb086ba11c385c27e545ebfa1997248Jeff Sharkey        if (pollFrequency < 60) {
4956009459405bbaa42054c9746c6339b48962c7753Jeff Sharkey            Slog.w(TAG, "Requested poll frequency of " + pollFrequency
49651366be80fb086ba11c385c27e545ebfa1997248Jeff Sharkey                    + " seconds being rounded up to 60 seconds.");
49751366be80fb086ba11c385c27e545ebfa1997248Jeff Sharkey            pollFrequency = 60;
4986009459405bbaa42054c9746c6339b48962c7753Jeff Sharkey        }
4996009459405bbaa42054c9746c6339b48962c7753Jeff Sharkey
500c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        long identityToken = clearCallingIdentity();
501c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        try {
502fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            // Add default flex time to this sync.
503fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            PeriodicSync syncToAdd =
504fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                    new PeriodicSync(account, authority, extras,
505fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                            pollFrequency,
506fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                            SyncStorageEngine.calculateDefaultFlexTime(pollFrequency));
507fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            getSyncManager().getSyncStorageEngine().addPeriodicSync(syncToAdd, userId);
508c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        } finally {
509c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            restoreCallingIdentity(identityToken);
510c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
511c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    }
512c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
513fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
514c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    public void removePeriodicSync(Account account, String authority, Bundle extras) {
515632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (account == null) {
516632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Account must not be null");
517632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
518632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (TextUtils.isEmpty(authority)) {
519632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Authority must not be empty");
520632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
521c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
522c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                "no permission to write the sync settings");
52304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
524632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
525c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        long identityToken = clearCallingIdentity();
526c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        try {
527fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            PeriodicSync syncToRemove = new PeriodicSync(account, authority, extras,
528fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams                    0 /* Not read for removal */, 0 /* Not read for removal */);
529fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams            getSyncManager().getSyncStorageEngine().removePeriodicSync(syncToRemove, userId);
530c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        } finally {
531c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            restoreCallingIdentity(identityToken);
532c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
533c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    }
534c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
535fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    /**
536fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * TODO: Implement.
537fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     * @param request Sync to remove.
538fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams     */
539fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    public void removeSync(SyncRequest request) {
540fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams
541fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    }
542fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams
543fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
544c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
545632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (account == null) {
546632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Account must not be null");
547632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
548632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (TextUtils.isEmpty(providerName)) {
549632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Authority must not be empty");
550632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
551c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
552c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana                "no permission to read the sync settings");
55304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
554632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
555c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        long identityToken = clearCallingIdentity();
556c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        try {
557c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
55804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    account, userId, providerName);
559c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        } finally {
560c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana            restoreCallingIdentity(identityToken);
561c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana        }
562c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana    }
563c5d1c6db61f208b206b260f897bb5bbc64be4d97Fred Quintana
5645e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    public int getIsSyncable(Account account, String providerName) {
5655e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
5665e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                "no permission to read the sync settings");
567f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
56804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
5695e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        long identityToken = clearCallingIdentity();
5705e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        try {
5715e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            SyncManager syncManager = getSyncManager();
5725e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            if (syncManager != null) {
5739422bdca314064fe82075b90cf529865c8053c44Amith Yamasani                return syncManager.getIsSyncable(
57404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName);
5755e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            }
5765e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        } finally {
5775e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            restoreCallingIdentity(identityToken);
5785e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        }
5795e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        return -1;
5805e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    }
5815e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana
582fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
5835e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    public void setIsSyncable(Account account, String providerName, int syncable) {
584632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (TextUtils.isEmpty(providerName)) {
585632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Authority must not be empty");
586632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
5875e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
5885e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                "no permission to write the sync settings");
58904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
590632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
5915e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        long identityToken = clearCallingIdentity();
5925e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        try {
5935e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            SyncManager syncManager = getSyncManager();
5945e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            if (syncManager != null) {
5955e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana                syncManager.getSyncStorageEngine().setIsSyncable(
59604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, providerName, syncable);
5975e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            }
5985e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        } finally {
5995e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana            restoreCallingIdentity(identityToken);
6005e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana        }
6015e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana    }
6025e787c42f2a6b3afc8ec8320a08d51b2d44b8614Fred Quintana
603fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
604ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public boolean getMasterSyncAutomatically() {
605231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
606231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync settings");
60704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
608632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
609231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
610231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
611231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
612231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
61304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
614231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
615231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
616231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
617231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
618231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
619231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
620b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
621fa77418134c6f1f80af225a78819f069e9c974fbMatthew Williams    @Override
622ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public void setMasterSyncAutomatically(boolean flag) {
623231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
624231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to write the sync settings");
62504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
626632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
627231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
628231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
629231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
630231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
63104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
632231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
633231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
634231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
635231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
636231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
637231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn
6387a1355950172b7a549820e9a2cd4a9b2099ec32fDianne Hackborn    public boolean isSyncActive(Account account, String authority) {
639231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
640231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
641f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        int userId = UserHandle.getCallingUserId();
64204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
643231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
644231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
645231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
646231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
647231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                return syncManager.getSyncStorageEngine().isSyncActive(
64804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, authority);
649231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
650231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
651231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
652231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
653231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
654231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
655b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
656c6a69559cb62bd20166c0c9684e64c60d779da38Fred Quintana    public List<SyncInfo> getCurrentSyncs() {
657231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
658231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
65904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
660632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
661231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
662231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
66304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId);
664231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
665231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
666231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
667231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
668b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
669ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public SyncStatusInfo getSyncStatus(Account account, String authority) {
670632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        if (TextUtils.isEmpty(authority)) {
671632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams            throw new IllegalArgumentException("Authority must not be empty");
672632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        }
673231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
674231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
67504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
676632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
677231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
678231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
679231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
680231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
681b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache                return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority(
68204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        account, userId, authority);
683231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
684231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
685231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
686231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
687231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return null;
688231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
689b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
690ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana    public boolean isSyncPending(Account account, String authority) {
691231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
692231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn                "no permission to read the sync stats");
69304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
694632515b9d0960749ddb1636677d7f12f196d73f7Matthew Williams        int userId = UserHandle.getCallingUserId();
695231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
696231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
697231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
698231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            if (syncManager != null) {
69904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return syncManager.getSyncStorageEngine().isSyncPending(account, userId, authority);
700231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
701231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
702231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
703231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
704231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        return false;
705231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
706b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
707231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
708231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
709231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
710231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
7111b487ec44b6b5594914d52fa427bec4f29a60541Fred Quintana            if (syncManager != null && callback != null) {
712ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
713231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
714231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
715231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
716231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
717231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
718b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
719231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    public void removeStatusChangeListener(ISyncStatusObserver callback) {
720231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        long identityToken = clearCallingIdentity();
721231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        try {
722231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            SyncManager syncManager = getSyncManager();
7231b487ec44b6b5594914d52fa427bec4f29a60541Fred Quintana            if (syncManager != null && callback != null) {
724ac9385ef3105fb7464e1f46049c62755a8b7f0e9Fred Quintana                syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
725231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            }
726231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        } finally {
727231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn            restoreCallingIdentity(identityToken);
728231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        }
729231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn    }
730b752098e8d12d6e7925d97458078dbb896ca8a05Costin Manolache
73126ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    public static ContentService main(Context context, boolean factoryTest) {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ContentService service = new ContentService(context, factoryTest);
733231cc608d06ffc31c24bf8aa8c8275bdd2636581Dianne Hackborn        ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return service;
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Hide this class since it is not part of api,
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * but current unittest framework requires it to be public
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final class ObserverNode {
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class ObserverEntry implements IBinder.DeathRecipient {
744002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana            public final IContentObserver observer;
7451b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public final int uid;
7461b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public final int pid;
74716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            public final boolean notifyForDescendants;
74816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            private final int userHandle;
749002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana            private final Object observersLock;
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7511b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
75216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    int _uid, int _pid, int _userHandle) {
753002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                this.observersLock = observersLock;
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                observer = o;
7551b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                uid = _uid;
7561b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pid = _pid;
75716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                userHandle = _userHandle;
75816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                notifyForDescendants = n;
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    observer.asBinder().linkToDeath(this, 0);
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    binderDied();
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
767002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                synchronized (observersLock) {
768002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                    removeObserverLocked(observer);
769002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7711b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn
7721b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
7731b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    String name, String prefix, SparseIntArray pidCounts) {
7741b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pidCounts.put(pid, pidCounts.get(pid)+1);
7751b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                pw.print(prefix); pw.print(name); pw.print(": pid=");
7761b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        pw.print(pid); pw.print(" uid=");
77716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        pw.print(uid); pw.print(" user=");
77816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        pw.print(userHandle); pw.print(" target=");
7791b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        pw.println(Integer.toHexString(System.identityHashCode(
7801b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                                observer != null ? observer.asBinder() : null)));
7811b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int INSERT_TYPE = 0;
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int UPDATE_TYPE = 1;
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DELETE_TYPE = 2;
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mName;
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ObserverNode(String name) {
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mName = name;
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7961b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn        public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
7971b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                String name, String prefix, int[] counts, SparseIntArray pidCounts) {
7981b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            String innerName = null;
7991b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            if (mObservers.size() > 0) {
8001b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                if ("".equals(name)) {
8011b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    innerName = mName;
8021b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                } else {
8031b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    innerName = name + "/" + mName;
8041b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
8051b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<mObservers.size(); i++) {
8061b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    counts[1]++;
8071b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
8081b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            pidCounts);
8091b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
8101b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
8111b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            if (mChildren.size() > 0) {
8121b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                if (innerName == null) {
8131b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    if ("".equals(name)) {
8141b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        innerName = mName;
8151b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    } else {
8161b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                        innerName = name + "/" + mName;
8171b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    }
8181b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
8191b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                for (int i=0; i<mChildren.size(); i++) {
8201b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    counts[0]++;
8211b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                    mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
8221b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                            counts, pidCounts);
8231b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn                }
8241b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn            }
8251b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn        }
8261b64e0d8657463c0f7ce9b068a16a522cdfe7d28Dianne Hackborn
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String getUriSegment(Uri uri, int index) {
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uri != null) {
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (index == 0) {
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return uri.getAuthority();
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return uri.getPathSegments().get(index - 1);
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int countUriSegments(Uri uri) {
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (uri == null) {
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return uri.getPathSegments().size() + 1;
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
84616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        // Invariant:  userHandle is either a hard user number or is USER_ALL
847002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        public void addObserverLocked(Uri uri, IContentObserver observer,
84816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean notifyForDescendants, Object observersLock,
84916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                int uid, int pid, int userHandle) {
85016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
85116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    uid, pid, userHandle);
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
854002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        private void addObserverLocked(Uri uri, int index, IContentObserver observer,
85516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean notifyForDescendants, Object observersLock,
85616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                int uid, int pid, int userHandle) {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If this is the leaf node add the observer
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index == countUriSegments(uri)) {
85916aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
86016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        uid, pid, userHandle));
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Look to see if the proper child already exists
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String segment = getUriSegment(uri, index);
866f51266471cb6c3e824435ae6e416012a62266d52Anthony Newnam            if (segment == null) {
867f51266471cb6c3e824435ae6e416012a62266d52Anthony Newnam                throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
868f51266471cb6c3e824435ae6e416012a62266d52Anthony Newnam            }
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mChildren.size();
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverNode node = mChildren.get(i);
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (node.mName.equals(segment)) {
87316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
87416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                            observersLock, uid, pid, userHandle);
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // No child found, create one
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ObserverNode node = new ObserverNode(segment);
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mChildren.add(node);
88216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate            node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
88316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    observersLock, uid, pid, userHandle);
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
886002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        public boolean removeObserverLocked(IContentObserver observer) {
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mChildren.size();
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
889002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana                boolean empty = mChildren.get(i).removeObserverLocked(observer);
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (empty) {
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mChildren.remove(i);
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    i--;
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    size--;
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IBinder observerBinder = observer.asBinder();
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            size = mObservers.size();
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverEntry entry = mObservers.get(i);
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (entry.observer.asBinder() == observerBinder) {
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mObservers.remove(i);
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We no longer need to listen for death notifications. Remove it.
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    observerBinder.unlinkToDeath(entry, 0);
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mChildren.size() == 0 && mObservers.size() == 0) {
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
915002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
91616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean observerWantsSelfNotifications, int targetUserHandle,
91716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                ArrayList<ObserverCall> calls) {
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mObservers.size();
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IBinder observerBinder = observer == null ? null : observer.asBinder();
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverEntry entry = mObservers.get(i);
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
92316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                // Don't notify the observer if it sent the notification and isn't interested
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // in self notifications
92586de0590b94bcce27e3038c27464bed510bb564aJeff Brown                boolean selfChange = (entry.observer.asBinder() == observerBinder);
92686de0590b94bcce27e3038c27464bed510bb564aJeff Brown                if (selfChange && !observerWantsSelfNotifications) {
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
93016aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                // Does this observer match the target user?
93116aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                if (targetUserHandle == UserHandle.USER_ALL
93216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        || entry.userHandle == UserHandle.USER_ALL
93316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        || targetUserHandle == entry.userHandle) {
93416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    // Make sure the observer is interested in the notification
93516aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    if (leaf || (!leaf && entry.notifyForDescendants)) {
93616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        calls.add(new ObserverCall(this, entry.observer, selfChange));
93716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                    }
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
94216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate        /**
94316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate         * targetUserHandle is either a hard user handle or is USER_ALL
94416aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate         */
945002ffad599964653186c01f8e07fadc82dc0aceeFred Quintana        public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
94616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                boolean observerWantsSelfNotifications, int targetUserHandle,
94716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                ArrayList<ObserverCall> calls) {
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String segment = null;
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int segmentCount = countUriSegments(uri);
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index >= segmentCount) {
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // This is the leaf node, notify all observers
95216aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
95316aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        targetUserHandle, calls);
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (index < segmentCount){
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                segment = getUriSegment(uri, index);
95616aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                // Notify any observers at this level who are interested in descendants
95716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
95816aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                        targetUserHandle, calls);
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int N = mChildren.size();
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ObserverNode node = mChildren.get(i);
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (segment == null || node.mName.equals(segment)) {
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // We found the child,
96686de0590b94bcce27e3038c27464bed510bb564aJeff Brown                    node.collectObserversLocked(uri, index + 1,
96716aa9736175f5bbe924a6e5587a2ca47c2dd702bChristopher Tate                            observer, observerWantsSelfNotifications, targetUserHandle, calls);
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (segment != null) {
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
976